diff options
| author | Shankar Easwaran <shankare@codeaurora.org> | 2013-06-16 05:06:28 +0000 | 
|---|---|---|
| committer | Shankar Easwaran <shankare@codeaurora.org> | 2013-06-16 05:06:28 +0000 | 
| commit | a42a4738935cd56c2426162f3f744dad1efa20da (patch) | |
| tree | e8f56bed7be2dd8664e4312b096cf131e19b6006 /lld/lib/ReaderWriter | |
| parent | 089ee1554c74f12bba8dddcf14cb62feeab6a08b (diff) | |
| download | bcm5719-llvm-a42a4738935cd56c2426162f3f744dad1efa20da.tar.gz bcm5719-llvm-a42a4738935cd56c2426162f3f744dad1efa20da.zip  | |
[ELF] add NMAGIC/OMAGIC support
llvm-svn: 184055
Diffstat (limited to 'lld/lib/ReaderWriter')
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Chunk.h | 15 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/DefaultLayout.h | 29 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp | 3 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/HeaderChunks.h | 21 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Reader.cpp | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/SectionChunks.h | 12 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/SegmentChunks.h | 78 | 
7 files changed, 144 insertions, 18 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Chunk.h b/lld/lib/ReaderWriter/ELF/Chunk.h index 667ca045297..811a20092ff 100644 --- a/lld/lib/ReaderWriter/ELF/Chunk.h +++ b/lld/lib/ReaderWriter/ELF/Chunk.h @@ -41,10 +41,19 @@ public:      K_AtomSection, ///< A section containing atoms.      K_SectionHeader ///< Section header    }; +  /// \brief the ContentType of the chunk +  enum ContentType { +    CT_Unknown, +    CT_Header, +    CT_Code, +    CT_Data, +    CT_Note, +    CT_Tls, +  }; +    Chunk(StringRef name, Kind kind, const ELFTargetInfo &ti)        : _name(name), _kind(kind), _fsize(0), _msize(0), _align2(0), _order(0), -        _ordinal(1), _start(0), _fileoffset(0), _targetInfo(ti) { -  } +        _ordinal(1), _start(0), _fileoffset(0), _targetInfo(ti) {}    virtual ~Chunk() {}    // Does the chunk occupy disk space    virtual bool occupiesNoDiskSpace() const { return false; } @@ -70,6 +79,8 @@ public:    // Does the chunk occupy memory during execution ?    uint64_t            memSize() const { return _msize; }    void setMemSize(uint64_t msize) { _msize = msize; } +  // Whats the contentType of the chunk ? +  virtual int getContentType() const = 0;    // Writer the chunk    virtual void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) = 0;    // Finalize the chunk before assigning offsets/virtual addresses diff --git a/lld/lib/ReaderWriter/ELF/DefaultLayout.h b/lld/lib/ReaderWriter/ELF/DefaultLayout.h index 96479a581d1..5124c0ee022 100644 --- a/lld/lib/ReaderWriter/ELF/DefaultLayout.h +++ b/lld/lib/ReaderWriter/ELF/DefaultLayout.h @@ -547,8 +547,9 @@ DefaultLayout<ELFT>::mergeSimiliarSections() {  template <class ELFT> void DefaultLayout<ELFT>::assignSectionsToSegments() {    ScopedTask task(getDefaultDomain(), "assignSectionsToSegments"); -  // TODO: Do we want to give a chance for the targetHandlers -  // to sort segments in an arbitrary order ? +  ELFTargetInfo::OutputMagic outputMagic = _targetInfo.getOutputMagic(); +    // TODO: Do we want to give a chance for the targetHandlers +    // to sort segments in an arbitrary order ?    // sort the sections by their order as defined by the layout    std::stable_sort(_sections.begin(), _sections.end(),                     [](Chunk<ELFT> *A, Chunk<ELFT> *B) { @@ -608,6 +609,14 @@ template <class ELFT> void DefaultLayout<ELFT>::assignSectionsToSegments() {            segment->append(section);          } +        // If the output magic is set to OutputMagic::NMAGIC or +        // OutputMagic::OMAGIC, Place the data alongside text in one single +        // segment +        if (outputMagic == ELFTargetInfo::OutputMagic::NMAGIC || +            outputMagic == ELFTargetInfo::OutputMagic::OMAGIC) +          lookupSectionFlag = llvm::ELF::SHF_EXECINSTR | llvm::ELF::SHF_ALLOC | +                              llvm::ELF::SHF_WRITE; +          // Use the flags of the merged Section for the segment          const SegmentKey key("PT_LOAD", lookupSectionFlag);          const std::pair<SegmentKey, Segment<ELFT> *> currentSegment(key, @@ -660,6 +669,7 @@ DefaultLayout<ELFT>::assignVirtualAddress() {      return;    uint64_t virtualAddress = _targetInfo.getBaseAddress(); +  ELFTargetInfo::OutputMagic outputMagic = _targetInfo.getOutputMagic();    // HACK: This is a super dirty hack. The elf header and program header are    // not part of a section, but we need them to be loaded at the base address @@ -690,9 +700,12 @@ DefaultLayout<ELFT>::assignVirtualAddress() {        // Dont assign offsets for non loadable segments        if (si->segmentType() != llvm::ELF::PT_LOAD)          continue; -      // Align the segment to a page boundary -      fileoffset = -          llvm::RoundUpToAlignment(fileoffset, _targetInfo.getPageSize()); +      // Align the segment to a page boundary only if the output mode is +      // not OutputMagic::NMAGIC/OutputMagic::OMAGIC +      if (outputMagic != ELFTargetInfo::OutputMagic::NMAGIC && +          outputMagic != ELFTargetInfo::OutputMagic::OMAGIC) +        fileoffset = +            llvm::RoundUpToAlignment(fileoffset, _targetInfo.getPageSize());        si->assignOffsets(fileoffset);        fileoffset = si->fileOffset() + si->fileSize();      } @@ -707,8 +720,10 @@ DefaultLayout<ELFT>::assignVirtualAddress() {        // first segment to the pagesize        (*si)->assignVirtualAddress(address);        (*si)->setMemSize(address - virtualAddress); -      virtualAddress = llvm::RoundUpToAlignment(address, -                                                _targetInfo.getPageSize()); +      if (outputMagic != ELFTargetInfo::OutputMagic::NMAGIC && +          outputMagic != ELFTargetInfo::OutputMagic::OMAGIC) +        virtualAddress = +            llvm::RoundUpToAlignment(address, _targetInfo.getPageSize());      }      _programHeader->resetProgramHeaders();    } diff --git a/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp b/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp index 8cd6c2dd7c2..c244f292e74 100644 --- a/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp +++ b/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp @@ -34,7 +34,8 @@ ELFTargetInfo::ELFTargetInfo(llvm::Triple triple,        _mergeCommonStrings(false),        _runLayoutPass(true),        _useShlibUndefines(false), -      _dynamicLinkerArg(false) {} +      _dynamicLinkerArg(false), +      _outputMagic(OutputMagic::DEFAULT) {}  bool ELFTargetInfo::is64Bits() const { return getTriple().isArch64Bit(); } diff --git a/lld/lib/ReaderWriter/ELF/HeaderChunks.h b/lld/lib/ReaderWriter/ELF/HeaderChunks.h index 95473d8b4ce..7da52c9e9b2 100644 --- a/lld/lib/ReaderWriter/ELF/HeaderChunks.h +++ b/lld/lib/ReaderWriter/ELF/HeaderChunks.h @@ -51,6 +51,10 @@ public:      return c->Kind() == Chunk<ELFT>::K_Header;    } +  inline int getContentType() const { +    return Chunk<ELFT>::CT_Header; +  } +    void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);    virtual void doPreFlight() {} @@ -162,6 +166,10 @@ public:      return _ph.size();    } +  inline int getContentType() const { +    return Chunk<ELFT>::CT_Header; +  } +  private:    Elf_Phdr *allocateProgramHeader(bool &allocatedNew) {      Elf_Phdr *phdr; @@ -185,6 +193,7 @@ private:  template <class ELFT>  bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {    bool allocatedNew = false; +  ELFTargetInfo::OutputMagic outputMagic = this->_targetInfo.getOutputMagic();    // For segments that are not a loadable segment, we    // just pick the values directly from the segment as there    // wouldnt be any slices within that @@ -213,8 +222,12 @@ bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {      phdr->p_filesz = slice->fileSize();      phdr->p_memsz = slice->memSize();      phdr->p_flags = segment->flags(); -    phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ? -                          segment->pageSize() : slice->align2(); +    if (outputMagic != ELFTargetInfo::OutputMagic::NMAGIC && +        outputMagic != ELFTargetInfo::OutputMagic::OMAGIC) +      phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ? segment->pageSize() +                                                           : slice->align2(); +    else +      phdr->p_align = slice->align2();    }    this->_fsize = fileSize();    this->_msize = this->_fsize; @@ -266,6 +279,10 @@ public:      return sizeof(Elf_Shdr);    } +  inline int getContentType() const { +    return Chunk<ELFT>::CT_Header; +  } +    inline uint64_t numHeaders() {      return _sectionInfo.size();    } diff --git a/lld/lib/ReaderWriter/ELF/Reader.cpp b/lld/lib/ReaderWriter/ELF/Reader.cpp index 73a61f4678a..0acfe5cf3fd 100644 --- a/lld/lib/ReaderWriter/ELF/Reader.cpp +++ b/lld/lib/ReaderWriter/ELF/Reader.cpp @@ -103,6 +103,10 @@ public:        break;      }      case llvm::sys::fs::file_magic::elf_shared_object: { +      // If the link doesnot allow dynamic libraries to be present during the +      // link, lets not parse the file and just return +      if (!_elfTargetInfo.allowLinkWithDynamicLibraries()) +        return llvm::make_error_code(llvm::errc::executable_format_error);        auto f = createELF<DynamicFileCreateELFTraits>(            getElfArchType(&*mb), MaxAlignment, _elfTargetInfo, std::move(mb));        if (!f) diff --git a/lld/lib/ReaderWriter/ELF/SectionChunks.h b/lld/lib/ReaderWriter/ELF/SectionChunks.h index 765a2795ad7..42c70b89d1b 100644 --- a/lld/lib/ReaderWriter/ELF/SectionChunks.h +++ b/lld/lib/ReaderWriter/ELF/SectionChunks.h @@ -78,6 +78,18 @@ public:    uint32_t getInfo() const { return _info; }    Layout::SegmentType getSegmentType() const { return _segmentType; } +  /// \brief Return the type of content that the section contains +  virtual int getContentType() const { +    if (_flags & llvm::ELF::SHF_EXECINSTR) +      return Chunk<ELFT>::CT_Code; +    else if (_flags & llvm::ELF::SHF_WRITE) +      return Chunk<ELFT>::CT_Data; +    else if (_flags & llvm::ELF::SHF_ALLOC) +      return Chunk<ELFT>::CT_Code; +    else +      return Chunk<ELFT>::CT_Unknown; +  } +    /// \brief convert the segment type to a String for diagnostics and printing    /// purposes    StringRef segmentKindToStr() const; diff --git a/lld/lib/ReaderWriter/ELF/SegmentChunks.h b/lld/lib/ReaderWriter/ELF/SegmentChunks.h index 453f905242a..05da29a06c5 100644 --- a/lld/lib/ReaderWriter/ELF/SegmentChunks.h +++ b/lld/lib/ReaderWriter/ELF/SegmentChunks.h @@ -114,6 +114,7 @@ public:    Segment(const ELFTargetInfo &ti, StringRef name,            const Layout::SegmentType type); +  /// \brief the Order of segments that appear in the output file    enum SegmentOrder {      permUnknown,      permRWX, @@ -199,8 +200,31 @@ public:      return _sections.size();    } +  /// \brief, this function returns the type of segment (PT_*)    inline Layout::SegmentType segmentType() { return _segmentType; } +  /// \brief return the segment type depending on the content, +  /// If the content corresponds to Code, this will return Segment::Code +  /// If the content corresponds to Data, this will return Segment::Data +  /// If the content corresponds to TLS, this will return Segment::TLS +  virtual int getContentType() const { +    int64_t fl = flags(); +    switch (_segmentType) { +    case llvm::ELF::PT_LOAD: { +      if (fl && llvm::ELF::PF_X) +        return Chunk<ELFT>::CT_Code; +      if (fl && llvm::ELF::PF_W) +        return Chunk<ELFT>::CT_Data; +    } +    case llvm::ELF::PT_TLS: +      return Chunk<ELFT>::CT_Tls; +    case llvm::ELF::PT_NOTE: +      return Chunk<ELFT>::CT_Note; +    default: +      return Chunk<ELFT>::CT_Unknown; +    } +  } +    inline int pageSize() const { return this->_targetInfo.getPageSize(); }    inline int rawflags() const { return _atomflags; } @@ -246,6 +270,19 @@ public:      return _segmentSlices.end();    } +private: + +  /// \brief Check if the chunk needs to be aligned +  bool needAlign(Chunk<ELFT> *chunk) const { +    if (chunk->getContentType() == Chunk<ELFT>::CT_Data && +        _outputMagic == ELFTargetInfo::OutputMagic::NMAGIC) +      return true; +    return false; +  } + +  // Cached value of outputMagic +  ELFTargetInfo::OutputMagic _outputMagic; +  protected:    /// \brief Section or some other chunk type.    std::vector<Chunk<ELFT> *> _sections; @@ -294,6 +331,7 @@ Segment<ELFT>::Segment(const ELFTargetInfo &ti, StringRef name,        _flags(0), _atomflags(0) {    this->_align2 = 0;    this->_fsize = 0; +  _outputMagic = ti.getOutputMagic();  }  // This function actually is used, but not in all instantiations of Segment. @@ -316,7 +354,7 @@ static DefinedAtom::ContentPermissions toAtomPerms(uint64_t flags) {  template <class ELFT> void Segment<ELFT>::append(Section<ELFT> *section) {    _sections.push_back(section);    if (_flags < section->getFlags()) -    _flags = section->getFlags(); +    _flags |= section->getFlags();    if (_atomflags < toAtomPerms(_flags))      _atomflags = toAtomPerms(_flags);    if (this->_align2 < section->align2()) @@ -385,8 +423,16 @@ template <class ELFT> void Segment<ELFT>::assignOffsets(uint64_t startOffset) {    endSectionIter = _sections.end();    startSection = 0;    bool isFirstSection = true; +  bool isDataPageAlignedForNMagic = false;    for (auto si = _sections.begin(); si != _sections.end(); ++si) {      if (isFirstSection) { +      // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data +      // to a page boundary +      if (!isDataPageAlignedForNMagic && needAlign(*si)) { +        startOffset = llvm::RoundUpToAlignment(startOffset, +                                               this->_targetInfo.getPageSize()); +        isDataPageAlignedForNMagic = true; +      }        // align the startOffset to the section alignment        uint64_t newOffset =          llvm::RoundUpToAlignment(startOffset, (*si)->align2()); @@ -398,12 +444,21 @@ template <class ELFT> void Segment<ELFT>::assignOffsets(uint64_t startOffset) {        isFirstSection = false;      } else {        uint64_t curOffset = curSliceFileOffset + curSliceSize; -      uint64_t newOffset = -        llvm::RoundUpToAlignment(curOffset, (*si)->align2()); +      // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data +      // to a page boundary +      if (!isDataPageAlignedForNMagic && needAlign(*si)) { +        curOffset = llvm::RoundUpToAlignment(curOffset, +                                             this->_targetInfo.getPageSize()); +        isDataPageAlignedForNMagic = true; +      } +      uint64_t newOffset = llvm::RoundUpToAlignment(curOffset, (*si)->align2());        SegmentSlice<ELFT> *slice = nullptr;        // If the newOffset computed is more than a page away, lets create        // a seperate segment, so that memory is not used up while running -      if ((newOffset - curOffset) > this->_targetInfo.getPageSize()) { +      if (((newOffset - curOffset) > this->_targetInfo.getPageSize()) && +          (_outputMagic != ELFTargetInfo::OutputMagic::NMAGIC && +           _outputMagic != ELFTargetInfo::OutputMagic::OMAGIC)) { +          // TODO: use std::find here          for (auto s : slices()) {            if (s->startSection() == startSection) { @@ -464,16 +519,27 @@ template <class ELFT> void Segment<ELFT>::assignOffsets(uint64_t startOffset) {  /// \brief Assign virtual addresses to the slices  template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t &addr) {    bool isTLSSegment = false; +  bool isDataPageAlignedForNMagic = false;    uint64_t tlsStartAddr = 0;    for (auto slice : slices()) { -    // Align to a page -    addr = llvm::RoundUpToAlignment(addr, this->_targetInfo.getPageSize()); +    // Align to a page only if the output is not +    // OutputMagic::NMAGIC/OutputMagic::OMAGIC +    if (_outputMagic != ELFTargetInfo::OutputMagic::NMAGIC && +        _outputMagic != ELFTargetInfo::OutputMagic::OMAGIC) +      addr = llvm::RoundUpToAlignment(addr, this->_targetInfo.getPageSize()); +      // Align to the slice alignment      addr = llvm::RoundUpToAlignment(addr, slice->align2());      bool virtualAddressSet = false;      for (auto section : slice->sections()) { +      // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data +      // to a page boundary +      if (!isDataPageAlignedForNMagic && needAlign(section)) { +        addr = llvm::RoundUpToAlignment(addr, this->_targetInfo.getPageSize()); +        isDataPageAlignedForNMagic = true; +      }        // Align the section address        addr = llvm::RoundUpToAlignment(addr, section->align2());        // Check if the segment is of type TLS  | 

