[lld] r239230 - COFF: Move .idata constructor from Writer to Chunk.

Rui Ueyama ruiu at google.com
Sat Jun 6 15:46:15 PDT 2015


Author: ruiu
Date: Sat Jun  6 17:46:15 2015
New Revision: 239230

URL: http://llvm.org/viewvc/llvm-project?rev=239230&view=rev
Log:
COFF: Move .idata constructor from Writer to Chunk.

Previously, half of the constructor for .idata contents was in Chunks.cpp
and the rest was in Writer.cpp. This patch moves the latter to Chunks.cpp.
Now IdataContents class manages everything for .idata section.

Modified:
    lld/trunk/COFF/Chunks.cpp
    lld/trunk/COFF/Chunks.h
    lld/trunk/COFF/Writer.cpp
    lld/trunk/COFF/Writer.h

Modified: lld/trunk/COFF/Chunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.cpp?rev=239230&r1=239229&r2=239230&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.cpp (original)
+++ lld/trunk/COFF/Chunks.cpp Sat Jun  6 17:46:15 2015
@@ -17,6 +17,7 @@
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/raw_ostream.h"
 
+using namespace llvm;
 using namespace llvm::object;
 using namespace llvm::support::endian;
 using namespace llvm::COFF;
@@ -25,6 +26,9 @@ using llvm::RoundUpToAlignment;
 namespace lld {
 namespace coff {
 
+const size_t LookupChunk::Size = sizeof(uint64_t);
+const size_t DirectoryChunk::Size = sizeof(ImportDirectoryTableEntry);
+
 SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H, uint32_t SI)
     : File(F), Header(H), SectionIndex(SI) {
   // Initialize SectionName.
@@ -196,31 +200,80 @@ void DirectoryChunk::writeTo(uint8_t *Bu
   E->ImportAddressTableRVA = AddressTab->getRVA();
 }
 
-ImportTable::ImportTable(StringRef N,
-                         std::vector<DefinedImportData *> &Symbols) {
-  // Create the import table hader.
-  DLLName = new StringChunk(N);
-  DirTab = new DirectoryChunk(DLLName);
-
-  // Create lookup and address tables. If they have external names,
-  // we need to create HintName chunks to store the names.
-  // If they don't (if they are import-by-ordinals), we store only
-  // ordinal values to the table.
-  for (DefinedImportData *S : Symbols) {
-    if (S->getExternalName().empty()) {
-      LookupTables.push_back(new OrdinalOnlyChunk(S->getOrdinal()));
-      AddressTables.push_back(new OrdinalOnlyChunk(S->getOrdinal()));
-      continue;
+// Returns a list of .idata contents.
+// See Microsoft PE/COFF spec 5.4 for details.
+std::vector<Chunk *> IdataContents::getChunks() {
+  create();
+  std::vector<Chunk *> V;
+  // The loader assumes a specific order of data.
+  // Add each type in the correct order.
+  for (std::unique_ptr<Chunk> &C : Dirs)
+    V.push_back(C.get());
+  for (std::unique_ptr<Chunk> &C : Lookups)
+    V.push_back(C.get());
+  for (std::unique_ptr<Chunk> &C : Addresses)
+    V.push_back(C.get());
+  for (std::unique_ptr<Chunk> &C : Hints)
+    V.push_back(C.get());
+  for (auto &P : DLLNames) {
+    std::unique_ptr<Chunk> &C = P.second;
+    V.push_back(C.get());
+  }
+  return V;
+}
+
+void IdataContents::create() {
+  // Group DLL-imported symbols by DLL name because that's how
+  // symbols are layed out in the import descriptor table.
+  std::map<StringRef, std::vector<DefinedImportData *>> Map;
+  for (DefinedImportData *Sym : Imports)
+    Map[Sym->getDLLName()].push_back(Sym);
+
+  // Create .idata contents for each DLL.
+  for (auto &P : Map) {
+    StringRef Name = P.first;
+    std::vector<DefinedImportData *> &Syms = P.second;
+
+    // Sort symbols by name for each group.
+    std::sort(Syms.begin(), Syms.end(),
+              [](DefinedImportData *A, DefinedImportData *B) {
+                return A->getName() < B->getName();
+              });
+
+    // Create lookup and address tables. If they have external names,
+    // we need to create HintName chunks to store the names.
+    // If they don't (if they are import-by-ordinals), we store only
+    // ordinal values to the table.
+    size_t Base = Lookups.size();
+    for (DefinedImportData *S : Syms) {
+      uint16_t Ord = S->getOrdinal();
+      if (S->getExternalName().empty()) {
+        Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord));
+        Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
+        continue;
+      }
+      auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
+      Lookups.push_back(make_unique<LookupChunk>(C.get()));
+      Addresses.push_back(make_unique<LookupChunk>(C.get()));
+      Hints.push_back(std::move(C));
     }
-    Chunk *C = new HintNameChunk(S->getExternalName(), S->getOrdinal());
-    HintNameTables.push_back(C);
-    LookupTables.push_back(new LookupChunk(C));
-    AddressTables.push_back(new LookupChunk(C));
-  }
-  for (int I = 0, E = Symbols.size(); I < E; ++I)
-    Symbols[I]->setLocation(AddressTables[I]);
-  DirTab->LookupTab = LookupTables[0];
-  DirTab->AddressTab = AddressTables[0];
+    // Terminate with null values.
+    Lookups.push_back(make_unique<NullChunk>(sizeof(uint64_t)));
+    Addresses.push_back(make_unique<NullChunk>(sizeof(uint64_t)));
+
+    for (int I = 0, E = Syms.size(); I < E; ++I)
+      Syms[I]->setLocation(Addresses[Base + I].get());
+
+    // Create the import table header.
+    if (!DLLNames.count(Name))
+      DLLNames[Name] = make_unique<StringChunk>(Name);
+    auto Dir = make_unique<DirectoryChunk>(DLLNames[Name].get());
+    Dir->LookupTab = Lookups[Base].get();
+    Dir->AddressTab = Addresses[Base].get();
+    Dirs.push_back(std::move(Dir));
+  }
+  // Add null terminator.
+  Dirs.push_back(make_unique<NullChunk>(DirectoryChunk::Size));
 }
 
 } // namespace coff

Modified: lld/trunk/COFF/Chunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.h?rev=239230&r1=239229&r2=239230&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.h (original)
+++ lld/trunk/COFF/Chunks.h Sat Jun  6 17:46:15 2015
@@ -169,6 +169,8 @@ private:
 // All chunks below are for the DLL import descriptor table and
 // Windows-specific. You may need to read the Microsoft PE/COFF spec
 // to understand details about the data structures.
+// If you are not particularly interested, you can skip them and
+// still be able to understand the rest of the linker.
 
 static const uint8_t ImportThunkData[] = {
     0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
@@ -202,8 +204,9 @@ private:
 class LookupChunk : public Chunk {
 public:
   explicit LookupChunk(Chunk *C) : HintName(C) {}
-  size_t getSize() const override { return sizeof(uint64_t); }
+  size_t getSize() const override { return Size; }
   void writeTo(uint8_t *Buf) override;
+  static const size_t Size;
   Chunk *HintName;
 };
 
@@ -222,17 +225,16 @@ public:
 class DirectoryChunk : public Chunk {
 public:
   explicit DirectoryChunk(Chunk *N) : DLLName(N) {}
-  size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
+  size_t getSize() const override { return Size; }
   void writeTo(uint8_t *Buf) override;
-
+  static const size_t Size;
   Chunk *DLLName;
   Chunk *LookupTab;
   Chunk *AddressTab;
 };
 
-// A chunk for the import descriptor table representing.
+// A chunk representing null terminator in the import table.
 // Contents of this chunk is always null bytes.
-// This is used for terminating import tables.
 class NullChunk : public Chunk {
 public:
   explicit NullChunk(size_t N) : Size(N) {}
@@ -243,16 +245,28 @@ private:
   size_t Size;
 };
 
-// ImportTable creates a set of import table chunks for a given
-// DLL-imported symbols.
-class ImportTable {
-public:
-  ImportTable(StringRef DLLName, std::vector<DefinedImportData *> &Symbols);
-  StringChunk *DLLName;
-  DirectoryChunk *DirTab;
-  std::vector<Chunk *> LookupTables;
-  std::vector<Chunk *> AddressTables;
-  std::vector<Chunk *> HintNameTables;
+// IdataContents creates all chunks for the .idata section.
+// You are supposed to call add() to add symbols and then
+// call getChunks() to get a list of chunks.
+class IdataContents {
+public:
+  void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
+  std::vector<Chunk *> getChunks();
+
+  uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
+  uint64_t getDirSize() { return Dirs.size() * DirectoryChunk::Size; }
+  uint64_t getIATRVA() { return Addresses[0]->getRVA(); }
+  uint64_t getIATSize() { return Addresses.size() * LookupChunk::Size; }
+
+private:
+  void create();
+
+  std::vector<DefinedImportData *> Imports;
+  std::vector<std::unique_ptr<Chunk>> Dirs;
+  std::vector<std::unique_ptr<Chunk>> Lookups;
+  std::vector<std::unique_ptr<Chunk>> Addresses;
+  std::vector<std::unique_ptr<Chunk>> Hints;
+  std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
 };
 
 } // namespace coff

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=239230&r1=239229&r2=239230&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Sat Jun  6 17:46:15 2015
@@ -128,83 +128,26 @@ void Writer::createSections() {
   }
 }
 
-std::map<StringRef, std::vector<DefinedImportData *>> Writer::binImports() {
-  // Group DLL-imported symbols by DLL name because that's how symbols
-  // are layed out in the import descriptor table.
-  std::map<StringRef, std::vector<DefinedImportData *>> Res;
+// Create .idata section contents.
+void Writer::createImportTables() {
+  if (Symtab->ImportFiles.empty())
+    return;
   OutputSection *Text = createSection(".text");
-  for (std::unique_ptr<ImportFile> &P : Symtab->ImportFiles) {
-    for (SymbolBody *B : P->getSymbols()) {
-      if (auto *Import = dyn_cast<DefinedImportData>(B)) {
-        Res[Import->getDLLName()].push_back(Import);
+  Idata.reset(new IdataContents());
+  for (std::unique_ptr<ImportFile> &File : Symtab->ImportFiles) {
+    for (SymbolBody *Body : File->getSymbols()) {
+      if (auto *Import = dyn_cast<DefinedImportData>(Body)) {
+        Idata->add(Import);
         continue;
       }
       // Linker-created function thunks for DLL symbols are added to
       // .text section.
-      Text->addChunk(cast<DefinedImportThunk>(B)->getChunk());
+      Text->addChunk(cast<DefinedImportThunk>(Body)->getChunk());
     }
   }
-
-  // Sort symbols by name for each group.
-  auto Comp = [](DefinedImportData *A, DefinedImportData *B) {
-    return A->getName() < B->getName();
-  };
-  for (auto &P : Res) {
-    std::vector<DefinedImportData *> &V = P.second;
-    std::sort(V.begin(), V.end(), Comp);
-  }
-  return Res;
-}
-
-// Create .idata section contents.
-void Writer::createImportTables() {
-  if (Symtab->ImportFiles.empty())
-    return;
-
-  std::vector<ImportTable> Tabs;
-  for (auto &P : binImports()) {
-    StringRef DLLName = P.first;
-    std::vector<DefinedImportData *> &Imports = P.second;
-    Tabs.emplace_back(DLLName, Imports);
-  }
-  OutputSection *Idata = createSection(".idata");
-  size_t NumChunks = Idata->getChunks().size();
-
-  // Add the directory tables.
-  for (ImportTable &T : Tabs)
-    Idata->addChunk(T.DirTab);
-  Idata->addChunk(new NullChunk(sizeof(ImportDirectoryTableEntry)));
-  ImportDirectoryTableSize = (Tabs.size() + 1) * sizeof(ImportDirectoryTableEntry);
-
-  // Add the import lookup tables.
-  for (ImportTable &T : Tabs) {
-    for (Chunk *C : T.LookupTables)
-      Idata->addChunk(C);
-    Idata->addChunk(new NullChunk(sizeof(uint64_t)));
-  }
-
-  // Add the import address tables. Their contents are the same as the
-  // lookup tables.
-  for (ImportTable &T : Tabs) {
-    for (Chunk *C : T.AddressTables)
-      Idata->addChunk(C);
-    Idata->addChunk(new NullChunk(sizeof(uint64_t)));
-    ImportAddressTableSize += (T.AddressTables.size() + 1) * sizeof(uint64_t);
-  }
-  ImportAddressTable = Tabs[0].AddressTables[0];
-
-  // Add the hint name table.
-  for (ImportTable &T : Tabs)
-    for (Chunk *C : T.HintNameTables)
-      Idata->addChunk(C);
-
-  // Add DLL names.
-  for (ImportTable &T : Tabs)
-    Idata->addChunk(T.DLLName);
-
-  // Claim ownership of all chunks in the .idata section.
-  for (size_t I = NumChunks, E = Idata->getChunks().size(); I < E; ++I)
-    Chunks.push_back(std::unique_ptr<Chunk>(Idata->getChunks()[I]));
+  OutputSection *Sec = createSection(".idata");
+  for (Chunk *C : Idata->getChunks())
+    Sec->addChunk(C);
 }
 
 // The Windows loader doesn't seem to like empty sections,
@@ -307,12 +250,11 @@ void Writer::writeHeader() {
   // Write data directory
   auto *DataDirectory = reinterpret_cast<data_directory *>(Buf);
   Buf += sizeof(*DataDirectory) * NumberfOfDataDirectory;
-  if (OutputSection *Idata = findSection(".idata")) {
-    using namespace llvm::COFF;
-    DataDirectory[IMPORT_TABLE].RelativeVirtualAddress = Idata->getRVA();
-    DataDirectory[IMPORT_TABLE].Size = ImportDirectoryTableSize;
-    DataDirectory[IAT].RelativeVirtualAddress = ImportAddressTable->getRVA();
-    DataDirectory[IAT].Size = ImportAddressTableSize;
+  if (Idata) {
+    DataDirectory[IMPORT_TABLE].RelativeVirtualAddress = Idata->getDirRVA();
+    DataDirectory[IMPORT_TABLE].Size = Idata->getDirSize();
+    DataDirectory[IAT].RelativeVirtualAddress = Idata->getIATRVA();
+    DataDirectory[IAT].Size = Idata->getIATSize();
   }
 
   // Section table

Modified: lld/trunk/COFF/Writer.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.h?rev=239230&r1=239229&r2=239230&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.h (original)
+++ lld/trunk/COFF/Writer.h Sat Jun  6 17:46:15 2015
@@ -94,9 +94,7 @@ private:
   std::unique_ptr<llvm::FileOutputBuffer> Buffer;
   llvm::SpecificBumpPtrAllocator<OutputSection> CAlloc;
   std::vector<OutputSection *> OutputSections;
-  Chunk *ImportAddressTable = nullptr;
-  uint32_t ImportDirectoryTableSize = 0;
-  uint32_t ImportAddressTableSize = 0;
+  std::unique_ptr<IdataContents> Idata;
 
   uint64_t FileSize;
   uint64_t SizeOfImage;





More information about the llvm-commits mailing list