Index: COFF/DLL.h =================================================================== --- COFF/DLL.h +++ COFF/DLL.h @@ -19,19 +19,12 @@ // Windows-specific. // IdataContents creates all chunks for the DLL import table. // You are supposed to call add() to add symbols and then -// call getChunks() to get a list of chunks. +// call create() to populate the chunk vectors. class IdataContents { public: void add(DefinedImportData *Sym) { Imports.push_back(Sym); } bool empty() { return Imports.empty(); } - std::vector getChunks(); - uint64_t getDirRVA() { return Dirs[0]->getRVA(); } - uint64_t getDirSize(); - uint64_t getIATRVA() { return Addresses[0]->getRVA(); } - uint64_t getIATSize(); - -private: void create(); std::vector Imports; Index: COFF/DLL.cpp =================================================================== --- COFF/DLL.cpp +++ COFF/DLL.cpp @@ -418,30 +418,6 @@ } // anonymous namespace -uint64_t IdataContents::getDirSize() { - return Dirs.size() * sizeof(ImportDirectoryTableEntry); -} - -uint64_t IdataContents::getIATSize() { - return Addresses.size() * ptrSize(); -} - -// Returns a list of .idata contents. -// See Microsoft PE/COFF spec 5.4 for details. -std::vector IdataContents::getChunks() { - create(); - - // The loader assumes a specific order of data. - // Add each type in the correct order. - std::vector V; - V.insert(V.end(), Dirs.begin(), Dirs.end()); - V.insert(V.end(), Lookups.begin(), Lookups.end()); - V.insert(V.end(), Addresses.begin(), Addresses.end()); - V.insert(V.end(), Hints.begin(), Hints.end()); - V.insert(V.end(), DLLNames.begin(), DLLNames.end()); - return V; -} - void IdataContents::create() { std::vector> V = binImports(Imports); Index: COFF/SymbolTable.cpp =================================================================== --- COFF/SymbolTable.cpp +++ COFF/SymbolTable.cpp @@ -69,7 +69,29 @@ } if (auto *F = dyn_cast(File)) { - ObjFile::Instances.push_back(F); + if (!F->ParentName.empty()) { + // TODO: + // Sort object files from within the same parent library alphabetically, + // to include the .idata headers before the individual imported functions. + // This is O(n^2) though (but could be implemented with one map per + // ParentName), and breaks code linking to msvcrt.lib (for some + // yet unknown reason). + // This requires adjustments to test/COFF/lto-comdat.ll. + auto Iter = ObjFile::Instances.begin(), End = ObjFile::Instances.end(); + for (; Iter != End; Iter++) { + if ((*Iter)->ParentName == F->ParentName) { + while (Iter != End && (*Iter)->ParentName == F->ParentName && + (*Iter)->getName() < F->getName()) + Iter++; + ObjFile::Instances.insert(Iter, F); + break; + } + } + if (Iter == End) + ObjFile::Instances.push_back(F); + } else { + ObjFile::Instances.push_back(F); + } } else if (auto *F = dyn_cast(File)) { BitcodeFile::Instances.push_back(F); } else if (auto *F = dyn_cast(File)) { Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -113,7 +113,8 @@ private: void createSections(); void createMiscChunks(); - void createImportTables(); + void createImportTables1(); + void createImportTables2(); void createExportTable(); void assignAddresses(); void removeEmptySections(); @@ -142,6 +143,10 @@ std::vector Strtab; std::vector OutputSymtab; IdataContents Idata; + Chunk *ImportTableStart = nullptr; + uint64_t ImportTableSize = 0; + Chunk *IATStart = nullptr; + uint64_t IATSize = 0; DelayLoadContents DelayIdata; EdataContents Edata; SEHTableChunk *SEHTable = nullptr; @@ -282,9 +287,24 @@ // The main function of the writer. void Writer::run() { + createImportTables1(); createSections(); createMiscChunks(); - createImportTables(); + + // Move .idata to the same spot as prior to this refactoring, to + // avoid changes in the output section order, to avoid changes to + // tests. This can be omitted later. + for (auto Iter = OutputSections.begin(), End = OutputSections.end(); + Iter != End; Iter++) { + OutputSection *Sec = *Iter; + if (Sec->getName() == ".idata") { + OutputSections.erase(Iter); + OutputSections.push_back(Sec); + break; + } + } + createImportTables2(); + createExportTable(); if (Config->Relocatable) createSection(".reloc"); @@ -341,11 +361,45 @@ Map[C->getSectionName()].push_back(C); } + if (!Idata.empty()) { + // Add the .idata content in the right section groups, to allow + // chunks from other linked in object files to be grouped together. + // See Microsoft PE/COFF spec 5.4 for details. + auto AddChunks = [&](StringRef N, std::vector &V) { + Map[N].insert(Map[N].end(), V.begin(), V.end()); + }; + // The loader assumes a specific order of data. + // Add each type in the correct order. + AddChunks(".idata$2", Idata.Dirs); + AddChunks(".idata$4", Idata.Lookups); + AddChunks(".idata$5", Idata.Addresses); + AddChunks(".idata$6", Idata.Hints); + AddChunks(".idata$7", Idata.DLLNames); + } + // Then create an OutputSection for each section. // '$' and all following characters in input section names are // discarded when determining output section. So, .text$foo // contributes to .text, for example. See PE/COFF spec 3.2. SmallDenseMap Sections; + + if (Map.find(".idata$2") != Map.end()) { + // Make sure to create .idata first with the right default permissions; + // none of the chunks set the IMAGE_SCN_CNT_INITIALIZED_DATA flag. + Sections[".idata"] = createSection(".idata"); + + std::vector &ImportTables = Map[".idata$2"]; + ImportTableStart = ImportTables.front(); + for (Chunk *C : ImportTables) + ImportTableSize += C->getSize(); + + std::vector &IAT = Map[".idata$5"]; + if (!IAT.empty()) + IATStart = IAT.front(); + for (Chunk *C : IAT) + IATSize += C->getSize(); + } + for (auto Pair : Map) { StringRef Name = getOutputSection(Pair.first); OutputSection *&Sec = Sections[Name]; @@ -415,10 +469,7 @@ // The format of this section is inherently Windows-specific. // IdataContents class abstracted away the details for us, // so we just let it create chunks and add them to the section. -void Writer::createImportTables() { - if (ImportFile::Instances.empty()) - return; - +void Writer::createImportTables1() { // Initialize DLLOrder so that import entries are ordered in // the same order as in the command line. (That affects DLL // initialization order, and this ordering is MSVC-compatible.) @@ -431,14 +482,10 @@ Config->DLLOrder[DLL] = Config->DLLOrder.size(); } - OutputSection *Text = createSection(".text"); for (ImportFile *File : ImportFile::Instances) { if (!File->Live) continue; - if (DefinedImportThunk *Thunk = File->ThunkSym) - Text->addChunk(Thunk->getChunk()); - if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { if (!File->ThunkSym) fatal("cannot delay-load " + toString(File) + @@ -449,10 +496,21 @@ } } - if (!Idata.empty()) { - OutputSection *Sec = createSection(".idata"); - for (Chunk *C : Idata.getChunks()) - Sec->addChunk(C); + if (!Idata.empty()) + Idata.create(); +} + +void Writer::createImportTables2() { + if (ImportFile::Instances.empty()) + return; + + OutputSection *Text = createSection(".text"); + for (ImportFile *File : ImportFile::Instances) { + if (!File->Live) + continue; + + if (DefinedImportThunk *Thunk = File->ThunkSym) + Text->addChunk(Thunk->getChunk()); } if (!DelayIdata.empty()) { @@ -713,11 +771,11 @@ Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA(); Dir[EXPORT_TABLE].Size = Sec->getVirtualSize(); } - if (!Idata.empty()) { - Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA(); - Dir[IMPORT_TABLE].Size = Idata.getDirSize(); - Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA(); - Dir[IAT].Size = Idata.getIATSize(); + if (ImportTableSize) { + Dir[IMPORT_TABLE].RelativeVirtualAddress = ImportTableStart->getRVA(); + Dir[IMPORT_TABLE].Size = ImportTableSize; + Dir[IAT].RelativeVirtualAddress = IATStart->getRVA(); + Dir[IAT].Size = IATSize; } if (OutputSection *Sec = findSection(".rsrc")) { Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA(); Index: test/COFF/lto-comdat.ll =================================================================== --- test/COFF/lto-comdat.ll +++ test/COFF/lto-comdat.ll @@ -36,8 +36,6 @@ ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-10 %s ; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat.lib -; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s -; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-10 %s ; HEADERS-11: AddressOfEntryPoint: 0x1000 ; TEXT-11: Disassembly of section .text: