[lld] r197016 - [PECOFF] Refactor IdataPass.

Rui Ueyama ruiu at google.com
Wed Dec 11 00:23:37 PST 2013


Author: ruiu
Date: Wed Dec 11 02:23:37 2013
New Revision: 197016

URL: http://llvm.org/viewvc/llvm-project?rev=197016&view=rev
Log:
[PECOFF] Refactor IdataPass.

This patch is to basically move the functionality to construct Data Directory
from IdataPass to WriterPECOFF.

Data Directory is a part of the PE/COFF header and contains the addresses of
the import tables.

We used to represent the link from Data Directory to the import tables as
relocation references. The idea behind it is that, because relocation
references are processed by the Writer, we wouldn't have to do anything special
to fill the addresses of the import tables. I thought that the addresses would
be set "automatically".

But it turned out that that design made the pass and the writer rather
complicated. In order to make relocation references between Data Directory to
the import tables, these data structures needed to be represented as Atom.
However, because Data Directory is not a section content but a part of the
PE/COFF header, it did not fit well as an Atom. So we ended up having
complicated code both in IdataPass and the writer.

This patch simplifies it.

One side effect of this patch is that we now have ".idata.a", ".idata.d" and
"idata.t" sections for the import address table, the import directory table,
and the import lookup table. The writer looks for the sections by name to find
the start addresses of the sections. We probably should have a better way to
find a specific atom from the core linking result, but currently using the
section name seems to be the easiest way to do that. The Windows loader do not
care about the import table's section layout.

Modified:
    lld/trunk/include/lld/Core/DefinedAtom.h
    lld/trunk/lib/Core/DefinedAtom.cpp
    lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h
    lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp
    lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h
    lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
    lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp

Modified: lld/trunk/include/lld/Core/DefinedAtom.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/DefinedAtom.h?rev=197016&r1=197015&r2=197016&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/DefinedAtom.h (original)
+++ lld/trunk/include/lld/Core/DefinedAtom.h Wed Dec 11 02:23:37 2013
@@ -144,7 +144,6 @@ public:
     typeTLVInitialData,     // initial data for a TLV [Darwin]
     typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
     typeTLVInitializerPtr,  // pointer to thread local initializer [Darwin]
-    typeDataDirectoryEntry, // linker created for data directory header [PECOFF]
     typeThreadZeroFill,     // Uninitialized thread local data(TBSS) [ELF]
     typeThreadData,         // Initialized thread local data(TDATA) [ELF]
     typeRONote,             // Identifies readonly note sections [ELF]

Modified: lld/trunk/lib/Core/DefinedAtom.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/DefinedAtom.cpp?rev=197016&r1=197015&r2=197016&view=diff
==============================================================================
--- lld/trunk/lib/Core/DefinedAtom.cpp (original)
+++ lld/trunk/lib/Core/DefinedAtom.cpp Wed Dec 11 02:23:37 2013
@@ -53,7 +53,6 @@ DefinedAtom::ContentPermissions DefinedA
   case typeLazyPointer:
   case typeLazyDylibPointer:
   case typeThunkTLV:
-  case typeDataDirectoryEntry:
   case typeRWNote:
     return permRW_;
 

Modified: lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h?rev=197016&r1=197015&r2=197016&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h Wed Dec 11 02:23:37 2013
@@ -246,18 +246,6 @@ private:
   std::vector<uint8_t> _data;
 };
 
-// A COFFDataDirectoryAtom represents an entry of Optional Data Directory in the
-// COFF header.
-class COFFDataDirectoryAtom : public COFFLinkerInternalAtom {
-public:
-  COFFDataDirectoryAtom(const File &file, uint64_t ordinal,
-                        std::vector<uint8_t> contents)
-      : COFFLinkerInternalAtom(file, ordinal, contents) {}
-
-  virtual ContentType contentType() const { return typeDataDirectoryEntry; }
-  virtual ContentPermissions permissions() const { return permR__; }
-};
-
 // A COFFSharedLibraryAtom represents a symbol for data in an import library.  A
 // reference to a COFFSharedLibraryAtom will be transformed to a real reference
 // to an import address table entry in Idata pass.

Modified: lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp?rev=197016&r1=197015&r2=197016&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp Wed Dec 11 02:23:37 2013
@@ -85,36 +85,36 @@ ImportTableEntryAtom::assembleRawContent
 void ImportDirectoryAtom::addRelocations(
     Context &context, StringRef loadName,
     const std::vector<COFFSharedLibraryAtom *> &sharedAtoms) {
-  size_t lookupEnd = context.importLookupTables.size();
-  size_t addressEnd = context.importAddressTables.size();
-
   // Create parallel arrays. The contents of the two are initially the
   // same. The PE/COFF loader overwrites the import address tables with the
   // pointers to the referenced items after loading the executable into
   // memory.
-  addImportTableAtoms(context, sharedAtoms, false, context.importLookupTables);
-  addImportTableAtoms(context, sharedAtoms, true, context.importAddressTables);
+  std::vector<ImportTableEntryAtom *> importLookupTables =
+      createImportTableAtoms(context, sharedAtoms, false, ".idata.t");
+  std::vector<ImportTableEntryAtom *> importAddressTables =
+      createImportTableAtoms(context, sharedAtoms, true, ".idata.a");
 
-  addDir32NBReloc(this, context.importLookupTables[lookupEnd],
+  addDir32NBReloc(this, importLookupTables[0],
                   offsetof(ImportDirectoryTableEntry, ImportLookupTableRVA));
-  addDir32NBReloc(this, context.importAddressTables[addressEnd],
+  addDir32NBReloc(this, importAddressTables[0],
                   offsetof(ImportDirectoryTableEntry, ImportAddressTableRVA));
   addDir32NBReloc(this, new (_alloc) DLLNameAtom(context, loadName),
                   offsetof(ImportDirectoryTableEntry, NameRVA));
 }
 
-void ImportDirectoryAtom::addImportTableAtoms(
+std::vector<ImportTableEntryAtom *> ImportDirectoryAtom::createImportTableAtoms(
     Context &context, const std::vector<COFFSharedLibraryAtom *> &sharedAtoms,
-    bool shouldAddReference, std::vector<ImportTableEntryAtom *> &ret) const {
+    bool shouldAddReference, StringRef sectionName) const {
+  std::vector<ImportTableEntryAtom *> ret;
   for (COFFSharedLibraryAtom *atom : sharedAtoms) {
     ImportTableEntryAtom *entry = nullptr;
     if (atom->importName().empty()) {
       // Import by ordinal
       uint32_t hint = (1U << 31) | atom->hint();
-      entry = new (_alloc) ImportTableEntryAtom(context, hint);
+      entry = new (_alloc) ImportTableEntryAtom(context, hint, sectionName);
     } else {
       // Import by name
-      entry = new (_alloc) ImportTableEntryAtom(context, 0);
+      entry = new (_alloc) ImportTableEntryAtom(context, 0, sectionName);
       HintNameAtom *hintName = createHintNameAtom(context, atom);
       addDir32NBReloc(entry, hintName);
     }
@@ -123,7 +123,8 @@ void ImportDirectoryAtom::addImportTable
       atom->setImportTableEntry(entry);
   }
   // Add the NULL entry.
-  ret.push_back(new (_alloc) ImportTableEntryAtom(context, 0));
+  ret.push_back(new (_alloc) ImportTableEntryAtom(context, 0, sectionName));
+  return ret;
 }
 
 HintNameAtom *ImportDirectoryAtom::createHintNameAtom(
@@ -151,7 +152,6 @@ void IdataPass::perform(std::unique_ptr<
   new (_alloc) idata::NullImportDirectoryAtom(context);
 
   connectAtoms(context);
-  createDataDirectoryAtoms(context);
   replaceSharedLibraryAtoms(context);
 }
 
@@ -183,48 +183,11 @@ void IdataPass::appendAtoms(std::vector<
 
 void IdataPass::connectAtoms(idata::Context &context) {
   std::vector<COFFBaseDefinedAtom *> atoms;
-  appendAtoms(atoms, context.importDirectories);
-  appendAtoms(atoms, context.importLookupTables);
-  appendAtoms(atoms, context.importAddressTables);
   appendAtoms(atoms, context.dllNameAtoms);
   appendAtoms(atoms, context.hintNameAtoms);
   coff::connectAtomsWithLayoutEdge(atoms);
 }
 
-/// The addresses of the import dirctory and the import address table needs to
-/// be set to the COFF Optional Data Directory header. A COFFDataDirectoryAtom
-/// represents the data directory header. We create a COFFDataDirectoryAtom
-/// and set relocations to them, so that the address will be set by the
-/// writer.
-void IdataPass::createDataDirectoryAtoms(idata::Context &context) {
-  // CLR_RUNTIME_HEADER is the last index of the data directory.
-  int nentries = llvm::COFF::CLR_RUNTIME_HEADER + 1;
-  int entSize = sizeof(llvm::object::data_directory);
-  std::vector<uint8_t> contents(nentries * entSize, 0);
-
-  auto importTableOffset =
-      llvm::COFF::DataDirectoryIndex::IMPORT_TABLE * entSize;
-  auto iatOffset = llvm::COFF::DataDirectoryIndex::IAT * entSize;
-
-  auto *importTableEntry = reinterpret_cast<llvm::object::data_directory *>(
-      &contents[0] + importTableOffset);
-  auto *iatEntry = reinterpret_cast<llvm::object::data_directory *>(
-      &contents[0] + iatOffset);
-
-  importTableEntry->Size =
-      context.importDirectories.size() * context.importDirectories[0]->size();
-  iatEntry->Size = context.importAddressTables.size() *
-                   context.importAddressTables[0]->size();
-
-  auto *dir = new (_alloc) coff::COFFDataDirectoryAtom(
-      context.dummyFile, context.dummyFile.getNextOrdinal(),
-      std::move(contents));
-  addDir32NBReloc(dir, context.importDirectories[0], importTableOffset);
-  addDir32NBReloc(dir, context.importAddressTables[0], iatOffset);
-
-  context.file.addAtom(*dir);
-}
-
 /// Transforms a reference to a COFFSharedLibraryAtom to a real reference.
 void IdataPass::replaceSharedLibraryAtoms(idata::Context &context) {
   for (const DefinedAtom *atom : context.file.defined()) {

Modified: lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h?rev=197016&r1=197015&r2=197016&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h Wed Dec 11 02:23:37 2013
@@ -58,8 +58,6 @@ struct Context {
   // accumulate all atoms created in the pass in the following vectors, and add
   // layout edges when finishing the pass.
   std::vector<COFFBaseDefinedAtom *> importDirectories;
-  std::vector<ImportTableEntryAtom *> importLookupTables;
-  std::vector<ImportTableEntryAtom *> importAddressTables;
   std::vector<HintNameAtom *> hintNameAtoms;
   std::vector<DLLNameAtom *> dllNameAtoms;
 
@@ -106,11 +104,16 @@ private:
 
 class ImportTableEntryAtom : public IdataAtom {
 public:
-  ImportTableEntryAtom(Context &context, uint32_t contents)
-      : IdataAtom(context, assembleRawContent(contents)) {}
+  ImportTableEntryAtom(Context &context, uint32_t contents,
+                       StringRef sectionName)
+      : IdataAtom(context, assembleRawContent(contents)),
+        _sectionName(sectionName) {}
+
+  virtual StringRef customSectionName() const { return _sectionName; };
 
 private:
   std::vector<uint8_t> assembleRawContent(uint32_t contents);
+  StringRef _sectionName;
 };
 
 /// An ImportDirectoryAtom includes information to load a DLL, including a DLL
@@ -126,12 +129,15 @@ public:
     context.importDirectories.push_back(this);
   }
 
+  virtual StringRef customSectionName() const { return ".idata.d"; }
+
 private:
   void addRelocations(Context &context, StringRef loadName,
                       const std::vector<COFFSharedLibraryAtom *> &sharedAtoms);
-  void addImportTableAtoms(
+
+  std::vector<ImportTableEntryAtom *> createImportTableAtoms(
       Context &context, const std::vector<COFFSharedLibraryAtom *> &sharedAtoms,
-      bool shouldAddReference, std::vector<ImportTableEntryAtom *> &ret) const;
+      bool shouldAddReference, StringRef sectionName) const;
   HintNameAtom *createHintNameAtom(Context &context,
                                    const COFFSharedLibraryAtom *atom) const;
 
@@ -145,6 +151,8 @@ public:
       : IdataAtom(context, std::vector<uint8_t>(20, 0)) {
     context.importDirectories.push_back(this);
   }
+
+  virtual StringRef customSectionName() const { return ".idata.d"; }
 };
 
 // An instance of this class represents "input file" for atoms created in this
@@ -181,7 +189,6 @@ private:
   void appendAtoms(std::vector<T *> &vec1, const std::vector<U *> &vec2);
 
   void connectAtoms(idata::Context &context);
-  void createDataDirectoryAtoms(idata::Context &context);
   void replaceSharedLibraryAtoms(idata::Context &context);
 
   // A dummy file with which all the atoms created in the pass will be

Modified: lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp?rev=197016&r1=197015&r2=197016&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp Wed Dec 11 02:23:37 2013
@@ -47,6 +47,7 @@
 
 using llvm::support::ulittle16_t;
 using llvm::support::ulittle32_t;
+using llvm::COFF::DataDirectoryIndex;
 
 namespace lld {
 namespace pecoff {
@@ -218,29 +219,20 @@ protected:
 /// header in the output file. An entry consists of an 8 byte field that
 /// indicates a relative virtual address (the starting address of the entry data
 /// in memory) and 8 byte entry data size.
-class DataDirectoryChunk : public AtomChunk {
+class DataDirectoryChunk : public HeaderChunk {
 public:
-  explicit DataDirectoryChunk(const DefinedAtom *atom)
-      : AtomChunk(kindDataDirectory) {
-    if (atom)
-      _atomLayouts.push_back(new (_alloc) AtomLayout(atom, 0, 0));
-  }
+  DataDirectoryChunk()
+      : HeaderChunk(), _data(std::vector<llvm::object::data_directory>(16)) {}
 
   virtual uint64_t size() const {
-    return sizeof(llvm::object::data_directory) * 16;
-  }
-
-  void setBaseRelocField(uint32_t addr, uint32_t size) {
-    _baseRelocAddr = addr;
-    _baseRelocSize = size;
+    return sizeof(llvm::object::data_directory) * _data.size();
   }
 
+  void setField(DataDirectoryIndex index, uint32_t addr, uint32_t size);
   virtual void write(uint8_t *buffer);
 
 private:
-  uint32_t _baseRelocAddr;
-  uint32_t _baseRelocSize;
-  mutable llvm::BumpPtrAllocator _alloc;
+  std::vector<llvm::object::data_directory> _data;
 };
 
 /// A SectionChunk represents a section containing atoms. It consists of a
@@ -561,22 +553,15 @@ void AtomChunk::addBaseRelocations(std::
   }
 }
 
-void DataDirectoryChunk::write(uint8_t *buffer) {
-  if (!_atomLayouts.empty()) {
-    assert(_atomLayouts.size() == 1);
-    const AtomLayout *layout = _atomLayouts[0];
-    ArrayRef<uint8_t> content =
-        static_cast<const DefinedAtom *>(layout->_atom)->rawContent();
-    std::memcpy(buffer, content.data(), content.size());
-  }
+void DataDirectoryChunk::setField(DataDirectoryIndex index, uint32_t addr,
+                                  uint32_t size) {
+  llvm::object::data_directory &dir = _data[index];
+  dir.RelativeVirtualAddress = addr;
+  dir.Size = size;
+}
 
-  // Write base relocation table entry.
-  int baseRelocOffset = llvm::COFF::DataDirectoryIndex::BASE_RELOCATION_TABLE *
-                        sizeof(llvm::object::data_directory);
-  auto *baseReloc = reinterpret_cast<llvm::object::data_directory *>(
-      buffer + baseRelocOffset);
-  baseReloc->RelativeVirtualAddress = _baseRelocAddr;
-  baseReloc->Size = _baseRelocSize;
+void DataDirectoryChunk::write(uint8_t *buffer) {
+  std::memcpy(buffer, &_data[0], size());
 }
 
 void SectionChunk::appendAtom(const DefinedAtom *atom) {
@@ -842,7 +827,7 @@ StringRef chooseSectionByContent(const D
 typedef std::map<StringRef, std::vector<const DefinedAtom *> > AtomVectorMap;
 
 void groupAtoms(const PECOFFLinkingContext &ctx, const File &file,
-                AtomVectorMap &result, const DefinedAtom *&datadir) {
+                AtomVectorMap &result) {
   for (const DefinedAtom *atom : file.defined()) {
     if (atom->sectionChoice() == DefinedAtom::sectionCustomRequired) {
       StringRef section = customSectionName(atom);
@@ -850,12 +835,8 @@ void groupAtoms(const PECOFFLinkingConte
       continue;
     }
     if (atom->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
-      if (atom->contentType() == DefinedAtom::typeDataDirectoryEntry) {
-        datadir = atom;
-      } else {
-        StringRef section = chooseSectionByContent(atom);
-        result[ctx.getOutputSectionName(section)].push_back(atom);
-      }
+      StringRef section = chooseSectionByContent(atom);
+      result[ctx.getOutputSectionName(section)].push_back(atom);
       continue;
     }
     llvm_unreachable("Unknown section choice");
@@ -865,13 +846,12 @@ void groupAtoms(const PECOFFLinkingConte
 // Create all chunks that consist of the output file.
 void ExecutableWriter::build(const File &linkedFile) {
   AtomVectorMap atoms;
-  const DefinedAtom *dataDirAtom = nullptr;
-  groupAtoms(_PECOFFLinkingContext, linkedFile, atoms, dataDirAtom);
+  groupAtoms(_PECOFFLinkingContext, linkedFile, atoms);
 
   // Create file chunks and add them to the list.
   auto *dosStub = new DOSStubChunk(_PECOFFLinkingContext);
   auto *peHeader = new PEHeaderChunk(_PECOFFLinkingContext);
-  auto *dataDirectory = new DataDirectoryChunk(dataDirAtom);
+  auto *dataDirectory = new DataDirectoryChunk();
   auto *sectionTable = new SectionHeaderTableChunk();
   addChunk(dosStub);
   addChunk(peHeader);
@@ -894,8 +874,9 @@ void ExecutableWriter::build(const File
     baseReloc->setContents(_chunks);
     if (baseReloc->size()) {
       addSectionChunk(baseReloc, sectionTable);
-      dataDirectory->setBaseRelocField(baseReloc->getVirtualAddress(),
-                                       baseReloc->rawSize());
+      dataDirectory->setField(DataDirectoryIndex::BASE_RELOCATION_TABLE,
+                              baseReloc->getVirtualAddress(),
+                              baseReloc->rawSize());
     }
   }
 
@@ -911,6 +892,12 @@ void ExecutableWriter::build(const File
     }
     if (section->getSectionName() == ".data")
       peHeader->setBaseOfData(section->getVirtualAddress());
+    if (section->getSectionName() == ".idata.a")
+      dataDirectory->setField(DataDirectoryIndex::IAT,
+                              section->getVirtualAddress(), section->rawSize());
+    if (section->getSectionName() == ".idata.d")
+      dataDirectory->setField(DataDirectoryIndex::IMPORT_TABLE,
+                              section->getVirtualAddress(), section->rawSize());
   }
 
   // Now that we know the size and file offset of sections. Set the file

Modified: lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp?rev=197016&r1=197015&r2=197016&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp (original)
+++ lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp Wed Dec 11 02:23:37 2013
@@ -445,8 +445,6 @@ template <> struct ScalarEnumerationTrai
     io.enumCase(value, "lto-temp", lld::DefinedAtom::typeTempLTO);
     io.enumCase(value, "compact-unwind",
                 lld::DefinedAtom::typeCompactUnwindInfo);
-    io.enumCase(value, "dataDirectoryEntry",
-                lld::DefinedAtom::typeDataDirectoryEntry);
     io.enumCase(value, "tlv-thunk", lld::DefinedAtom::typeThunkTLV);
     io.enumCase(value, "tlv-data", lld::DefinedAtom::typeTLVInitialData);
     io.enumCase(value, "tlv-zero-fill",





More information about the llvm-commits mailing list