From fd99e01b91dcb33c1459cf84d0d655b340177d09 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Mon, 1 Jun 2015 21:05:27 +0000 Subject: [PATCH] COFF: Support import-by-ordinal DLL imports. Symbols exported by DLLs can be imported not by name but by small number or ordinal. Usually, symbols have both ordinals and names, and in that case ordinals are called "hints" and used by the loader as hints. However, symbols can have only ordinals. They are called import-by-ordinal symbols. You need to manage ordinals by hand so that they will never change if you choose to use the feature. But it's supposed to make dynamic linking faster because it needs no string comparison. Not sure if that claim still stands in year 2015, though. Anyways, the feature exists, and this patch implements that. llvm-svn: 238780 --- lld/COFF/Chunks.cpp | 29 +++++++++++++++++++++-------- lld/COFF/Chunks.h | 12 ++++++++++++ lld/COFF/InputFiles.cpp | 6 +++++- lld/COFF/Symbols.h | 10 +++++----- lld/test/COFF/Inputs/hello64.asm | 2 ++ lld/test/COFF/Inputs/hello64.obj | Bin 632 -> 682 bytes lld/test/COFF/Inputs/std64.lib | Bin 1870 -> 2068 bytes lld/test/COFF/imports.test | 13 ++++++++----- 8 files changed, 53 insertions(+), 19 deletions(-) diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index 3a64a78..5a151ea 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -186,6 +186,12 @@ void LookupChunk::applyRelocations(uint8_t *Buf) { write32le(Buf + FileOff, HintName->getRVA()); } +void OrdinalOnlyChunk::writeTo(uint8_t *Buf) { + // An import-by-ordinal slot has MSB 1 to indicate that + // this is import-by-ordinal (and not import-by-name). + write64le(Buf + FileOff, (uint64_t(1) << 63) | Ordinal); +} + void DirectoryChunk::applyRelocations(uint8_t *Buf) { auto *E = (coff_import_directory_table_entry *)(Buf + FileOff); E->ImportLookupTableRVA = LookupTab->getRVA(); @@ -195,20 +201,27 @@ void DirectoryChunk::applyRelocations(uint8_t *Buf) { ImportTable::ImportTable(StringRef N, std::vector &Symbols) { + // Create the import table hader. DLLName = new StringChunk(N); DirTab = new DirectoryChunk(DLLName); - for (DefinedImportData *S : Symbols) - HintNameTables.push_back( - new HintNameChunk(S->getExportName(), S->getOrdinal())); - for (Chunk *H : HintNameTables) { - LookupTables.push_back(new LookupChunk(H)); - AddressTables.push_back(new LookupChunk(H)); + // 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; + } + 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]; } diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h index c4dc728..967f9427 100644 --- a/lld/COFF/Chunks.h +++ b/lld/COFF/Chunks.h @@ -214,6 +214,18 @@ public: }; // A chunk for the import descriptor table. +// This chunk represent import-by-ordinal symbols. +// See the Microsoft PE/COFF spec 7.1. Import Header for details. +class OrdinalOnlyChunk : public Chunk { +public: + explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {} + bool hasData() const override { return true; } + size_t getSize() const override { return sizeof(uint64_t); } + void writeTo(uint8_t *Buf) override; + uint16_t Ordinal; +}; + +// A chunk for the import descriptor table. class DirectoryChunk : public Chunk { public: explicit DirectoryChunk(Chunk *N) : DLLName(N) {} diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp index e2a597a..0205328 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -229,7 +229,11 @@ std::error_code ImportFile::parse() { StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr))); StringRef ImpName = StringAlloc.save(Twine("__imp_") + Name); StringRef DLLName(Buf + sizeof(coff_import_header) + Name.size() + 1); - auto *ImpSym = new (Alloc) DefinedImportData(DLLName, ImpName, Name, Hdr); + StringRef ExternalName = Name; + if (Hdr->getNameType() == llvm::COFF::IMPORT_ORDINAL) + ExternalName = ""; + auto *ImpSym = new (Alloc) DefinedImportData(DLLName, ImpName, ExternalName, + Hdr); SymbolBodies.push_back(ImpSym); // If type is function, we need to create a thunk which jump to an diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h index 4641ece..f866718 100644 --- a/lld/COFF/Symbols.h +++ b/lld/COFF/Symbols.h @@ -207,10 +207,10 @@ private: // table in an output. The former has "__imp_" prefix. class DefinedImportData : public Defined { public: - DefinedImportData(StringRef D, StringRef ImportName, StringRef ExportName, + DefinedImportData(StringRef D, StringRef Name, StringRef E, const coff_import_header *H) - : Defined(DefinedImportDataKind, ImportName), DLLName(D), - ExpName(ExportName), Hdr(H) {} + : Defined(DefinedImportDataKind, Name), DLLName(D), + ExternalName(E), Hdr(H) {} static bool classof(const SymbolBody *S) { return S->kind() == DefinedImportDataKind; @@ -219,13 +219,13 @@ public: uint64_t getRVA() override { return Location->getRVA(); } uint64_t getFileOff() override { return Location->getFileOff(); } StringRef getDLLName() { return DLLName; } - StringRef getExportName() { return ExpName; } + StringRef getExternalName() { return ExternalName; } void setLocation(Chunk *AddressTable) { Location = AddressTable; } uint16_t getOrdinal() { return Hdr->OrdinalHint; } private: StringRef DLLName; - StringRef ExpName; + StringRef ExternalName; const coff_import_header *Hdr; Chunk *Location = nullptr; }; diff --git a/lld/test/COFF/Inputs/hello64.asm b/lld/test/COFF/Inputs/hello64.asm index 1aa5629..6605213 100644 --- a/lld/test/COFF/Inputs/hello64.asm +++ b/lld/test/COFF/Inputs/hello64.asm @@ -3,6 +3,7 @@ extern ExitProcess : PROC extern MessageBoxA : PROC +extern ImportByOrdinal: PROC .data caption db 'Hello', 0 @@ -18,5 +19,6 @@ main PROC call MessageBoxA mov ecx, 0 call ExitProcess + call ImportByOrdinal main ENDP END diff --git a/lld/test/COFF/Inputs/hello64.obj b/lld/test/COFF/Inputs/hello64.obj index 0ae241e2013e6420598edacd7e5f03876e3e9e5f..90c1ce4aa4cffa94a14f160b7966706f9bea3c79 100644 GIT binary patch delta 174 zcmeytvWk^ArHz?k{hplACPoGZzKOizy2cC)3_U=60Ej_=6^IoW0uuC65=#=nA`n6t zNPU_ZsLsU7II+sX_yt&$4@hzYF$;qzkmLcg6o4crn56|IIlwG^AjviH?rBz#ZLE{m mGFF1DVUU?D$>hwaGdY$?TEH{6Ait=@snWkFB{MHEhXDXne;h^t delta 118 zcmZ3*`h$fxrHz?k>Y9|$B1Q%V-if^8x_S%@3_U=+3y4901&9?G0uuC65=#=nA`n6t zNIjYusLu42VPcg7KOd0G1;i{2qCk>+;(5u5pN_GD3}czRm$7oP2a_42%;b6|X#ghi B7QX-h diff --git a/lld/test/COFF/Inputs/std64.lib b/lld/test/COFF/Inputs/std64.lib index 9c47d4f6accc9f97f2f86d1b72cdf1c6a8d7b2b0..bbd223c59f4019318439addf29213e25c435d77d 100644 GIT binary patch delta 462 zcmX@dH$`BAG`q2(rJ<>T$>a}=VkSn0MhXy+z{SA8z{$YCWW>P062id1+QGoUb`OHt z*D)}Fu?vuPnY@--Ih1J|Ba#xa$r>yI ztRQ9ECl|8HPmW=Ej3OJuD!>es-JH*=hOA9|vLw4ONMiCyHX|er;(BJVZ~%q(|NjgO aDQzIrr9fT>Vsr=JWs^hJ4mVbxT^;~wMsx@O delta 320 zcmbOtaE@<+G`o?R84y`a&SMeNF*Gw%fPe%p1_lOp1_s7!3=GUa7#LV}7#P@^p!fxl zeld9+qw&P~!BYBA9Wct!#2Cp)M?-Ujk*q*7uQ4(({9tBa&;fFq*ccdI05Q-W1{MZZ z21W)ZFwM;1T9H{2P?VpXT3kGNA!Ed3ekL=xL*v-RB`i$g?o4T8X6V_J63PxVm}Bxq zR{kKY0hsV