[lld] r226335 - PE/COFF: rework how we handle base relocations

Saleem Abdulrasool compnerd at compnerd.org
Fri Jan 16 14:34:10 PST 2015


Author: compnerd
Date: Fri Jan 16 16:34:10 2015
New Revision: 226335

URL: http://llvm.org/viewvc/llvm-project?rev=226335&view=rev
Log:
PE/COFF: rework how we handle base relocations

Generalise the base relocation handling slightly to support multiple base
relocation types in PE/COFF.  This is necessary to generate proper executables
for WoA.

Track the base relocation type from the decision that we need a base relocation
to the point where we emit the base relocation into base relocation directory.

Remove an outdated TODO item while in the area.

Modified:
    lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp

Modified: lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp?rev=226335&r1=226334&r2=226335&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp Fri Jan 16 16:34:10 2015
@@ -250,6 +250,9 @@ private:
 /// An AtomChunk represents a section containing atoms.
 class AtomChunk : public SectionChunk {
 public:
+  typedef std::pair<uint64_t, llvm::COFF::BaseRelocationType> BaseRelocation;
+  typedef std::vector<BaseRelocation> BaseRelocationList;
+
   AtomChunk(const PECOFFLinkingContext &ctx, StringRef name,
             const std::vector<const DefinedAtom *> &atoms);
 
@@ -273,7 +276,7 @@ public:
                            uint64_t imageBaseAddress);
 
   void printAtomAddresses(uint64_t baseAddr) const;
-  void addBaseRelocations(std::vector<uint64_t> &relocSites) const;
+  void addBaseRelocations(BaseRelocationList &relocSites) const;
 
   void setVirtualAddress(uint32_t rva) override;
   uint64_t getAtomVirtualAddress(StringRef name) const;
@@ -335,9 +338,12 @@ private:
 /// executable.
 class BaseRelocChunk : public SectionChunk {
   typedef std::vector<std::unique_ptr<Chunk> > ChunkVectorT;
-  typedef std::map<uint64_t, std::vector<uint16_t> > PageOffsetT;
 
 public:
+  typedef std::pair<uint16_t, llvm::COFF::BaseRelocationType> BaseRelocation;
+  typedef std::vector<BaseRelocation> BaseRelocations;
+  typedef std::map<uint64_t, BaseRelocations> RelocationBlocks;
+
   BaseRelocChunk(ChunkVectorT &chunks, const PECOFFLinkingContext &ctx)
       : SectionChunk(kindSection, ".reloc", characteristics, ctx),
         _ctx(ctx), _contents(createContents(chunks)) {}
@@ -359,15 +365,15 @@ private:
 
   // Returns a list of RVAs that needs to be relocated if the binary is loaded
   // at an address different from its preferred one.
-  std::vector<uint64_t> listRelocSites(ChunkVectorT &chunks) const;
+  AtomChunk::BaseRelocationList listRelocSites(ChunkVectorT &chunks) const;
 
   // Divide the given RVAs into blocks.
-  PageOffsetT groupByPage(const std::vector<uint64_t> &relocSites) const;
+  RelocationBlocks
+  groupByPage(const AtomChunk::BaseRelocationList &relocSites) const;
 
   // Create the content of a relocation block.
   std::vector<uint8_t>
-  createBaseRelocBlock(uint64_t pageAddr,
-                       const std::vector<uint16_t> &offsets) const;
+  createBaseRelocBlock(uint64_t pageAddr, const BaseRelocations &relocs) const;
 
   const PECOFFLinkingContext &_ctx;
   std::vector<uint8_t> _contents;
@@ -755,33 +761,36 @@ void AtomChunk::printAtomAddresses(uint6
 /// to be fixed up if image base is relocated. The only relocation type that
 /// needs to be fixed is DIR32 on i386. REL32 is not (and should not be)
 /// fixed up because it's PC-relative.
-void AtomChunk::addBaseRelocations(std::vector<uint64_t> &relocSites) const {
-  // TODO: llvm-objdump doesn't support parsing the base relocation table, so
-  // we can't really test this at the moment. As a temporary solution, we
-  // should output debug messages with atom names and addresses so that we
-  // can inspect relocations, and fix the tests (base-reloc.test, maybe
-  // others) to use those messages.
-
-  int16_t relType = 0; /* IMAGE_REL_*_ABSOLUTE */
-  switch (_machineType) {
-  default: llvm_unreachable("unsupported machine type");
-  case llvm::COFF::IMAGE_FILE_MACHINE_I386:
-    relType = llvm::COFF::IMAGE_REL_I386_DIR32;
-    break;
-  case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
-    relType = llvm::COFF::IMAGE_REL_AMD64_ADDR64;
-    break;
-  case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
-    relType = llvm::COFF::IMAGE_REL_ARM_ADDR32;
-    break;
-  }
-
+void AtomChunk::addBaseRelocations(BaseRelocationList &relocSites) const {
   for (const auto *layout : _atomLayouts) {
     const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
-    for (const Reference *ref : *atom)
-      if ((ref->kindNamespace() == Reference::KindNamespace::COFF) &&
-          (ref->kindValue() == relType))
-        relocSites.push_back(layout->_virtualAddr + ref->offsetInAtom());
+    for (const Reference *ref : *atom) {
+      if (ref->kindNamespace() != Reference::KindNamespace::COFF)
+        continue;
+
+      uint64_t address = layout->_virtualAddr + ref->offsetInAtom();
+      switch (_machineType) {
+      default: llvm_unreachable("unsupported machine type");
+      case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+        if (ref->kindValue() == llvm::COFF::IMAGE_REL_I386_DIR32)
+          relocSites.push_back(
+              std::make_pair(address, llvm::COFF::IMAGE_REL_BASED_HIGHLOW));
+        break;
+      case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+        if (ref->kindValue() == llvm::COFF::IMAGE_REL_AMD64_ADDR64)
+          relocSites.push_back(
+              std::make_pair(address, llvm::COFF::IMAGE_REL_BASED_DIR64));
+        break;
+      case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
+        if (ref->kindValue() == llvm::COFF::IMAGE_REL_ARM_ADDR32)
+          relocSites.push_back(
+              std::make_pair(address, llvm::COFF::IMAGE_REL_BASED_HIGHLOW));
+        else if (ref->kindValue() == llvm::COFF::IMAGE_REL_ARM_MOV32T)
+          relocSites.push_back(
+              std::make_pair(address, llvm::COFF::IMAGE_REL_BASED_ARM_MOV32T));
+        break;
+      }
+    }
   }
 }
 
@@ -925,12 +934,12 @@ SectionHeaderTableChunk::createSectionHe
 std::vector<uint8_t>
 BaseRelocChunk::createContents(ChunkVectorT &chunks) const {
   std::vector<uint8_t> contents;
-  std::vector<uint64_t> relocSites = listRelocSites(chunks);
-  PageOffsetT blocks = groupByPage(relocSites);
+  AtomChunk::BaseRelocationList relocSites = listRelocSites(chunks);
+  RelocationBlocks blocks = groupByPage(relocSites);
   for (auto &i : blocks) {
     uint64_t pageAddr = i.first;
-    const std::vector<uint16_t> &offsetsInPage = i.second;
-    std::vector<uint8_t> block = createBaseRelocBlock(pageAddr, offsetsInPage);
+    const BaseRelocations &relocs = i.second;
+    std::vector<uint8_t> block = createBaseRelocBlock(pageAddr, relocs);
     contents.insert(contents.end(), block.begin(), block.end());
   }
   return contents;
@@ -938,9 +947,9 @@ BaseRelocChunk::createContents(ChunkVect
 
 // Returns a list of RVAs that needs to be relocated if the binary is loaded
 // at an address different from its preferred one.
-std::vector<uint64_t>
+AtomChunk::BaseRelocationList
 BaseRelocChunk::listRelocSites(ChunkVectorT &chunks) const {
-  std::vector<uint64_t> ret;
+  AtomChunk::BaseRelocationList ret;
   for (auto &cp : chunks)
     if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
       chunk->addBaseRelocations(ret);
@@ -948,22 +957,24 @@ BaseRelocChunk::listRelocSites(ChunkVect
 }
 
 // Divide the given RVAs into blocks.
-BaseRelocChunk::PageOffsetT
-BaseRelocChunk::groupByPage(const std::vector<uint64_t> &relocSites) const {
-  PageOffsetT blocks;
+BaseRelocChunk::RelocationBlocks BaseRelocChunk::groupByPage(
+    const AtomChunk::BaseRelocationList &relocSites) const {
+  RelocationBlocks blocks;
   uint64_t mask = _ctx.getPageSize() - 1;
-  for (uint64_t addr : relocSites)
-    blocks[addr & ~mask].push_back(addr & mask);
+  for (const auto &reloc : relocSites)
+    blocks[reloc.first & ~mask].push_back(
+        std::make_pair(reloc.first & mask, reloc.second));
   return blocks;
 }
 
 // Create the content of a relocation block.
-std::vector<uint8_t> BaseRelocChunk::createBaseRelocBlock(
-    uint64_t pageAddr, const std::vector<uint16_t> &offsets) const {
+std::vector<uint8_t>
+BaseRelocChunk::createBaseRelocBlock(uint64_t pageAddr,
+                                     const BaseRelocations &relocs) const {
   // Relocation blocks should be padded with IMAGE_REL_I386_ABSOLUTE to be
   // aligned to a DWORD size boundary.
   uint32_t size = llvm::RoundUpToAlignment(
-      sizeof(ulittle32_t) * 2 + sizeof(ulittle16_t) * offsets.size(),
+      sizeof(ulittle32_t) * 2 + sizeof(ulittle16_t) * relocs.size(),
       sizeof(ulittle32_t));
   std::vector<uint8_t> contents(size);
   uint8_t *ptr = &contents[0];
@@ -977,12 +988,9 @@ std::vector<uint8_t> BaseRelocChunk::cre
   *reinterpret_cast<ulittle32_t *>(ptr) = size;
   ptr += sizeof(ulittle32_t);
 
-  // The rest of the block consists of offsets in the page.
-  uint16_t type = _ctx.is64Bit() ? llvm::COFF::IMAGE_REL_BASED_DIR64
-                                 : llvm::COFF::IMAGE_REL_BASED_HIGHLOW;
-  for (uint16_t offset : offsets) {
-    assert(offset < _ctx.getPageSize());
-    *reinterpret_cast<ulittle16_t *>(ptr) = (type << 12) | offset;
+  for (const auto &reloc : relocs) {
+    assert(reloc.first < _ctx.getPageSize());
+    *reinterpret_cast<ulittle16_t *>(ptr) = (reloc.second << 12) | reloc.first;
     ptr += sizeof(ulittle16_t);
   }
   return contents;





More information about the llvm-commits mailing list