COFF: Move .idata constructor from Writer to Chunk.
authorRui Ueyama <ruiu@google.com>
Sat, 6 Jun 2015 22:46:15 +0000 (22:46 +0000)
committerRui Ueyama <ruiu@google.com>
Sat, 6 Jun 2015 22:46:15 +0000 (22:46 +0000)
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.

llvm-svn: 239230

lld/COFF/Chunks.cpp
lld/COFF/Chunks.h
lld/COFF/Writer.cpp
lld/COFF/Writer.h

index 7d8fbaf..372471f 100644 (file)
@@ -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 *Buf) {
   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));
+    // 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));
   }
-  for (int I = 0, E = Symbols.size(); I < E; ++I)
-    Symbols[I]->setLocation(AddressTables[I]);
-  DirTab->LookupTab = LookupTables[0];
-  DirTab->AddressTab = AddressTables[0];
+  // Add null terminator.
+  Dirs.push_back(make_unique<NullChunk>(DirectoryChunk::Size));
 }
 
 } // namespace coff
index b821a7f..00ae3ae 100644 (file)
@@ -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 {
+// 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:
-  ImportTable(StringRef DLLName, std::vector<DefinedImportData *> &Symbols);
-  StringChunk *DLLName;
-  DirectoryChunk *DirTab;
-  std::vector<Chunk *> LookupTables;
-  std::vector<Chunk *> AddressTables;
-  std::vector<Chunk *> HintNameTables;
+  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
index 482fa47..6beede3 100644 (file)
@@ -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
index 4705435..75558d3 100644 (file)
@@ -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;