[LLD][COFF] Set OrdinalBase to 1 for export table

Before this, LLD sets OrdinalBase to 0, which deviates from usual
practices. This technically would allow LLD to export a symbol using
ordinal 0, however LLD never use export ordinal 0, which results in
binaries with export tables always having an empty export at ordinal 0.

This change makes LLD set OrdinalBase to 1 and not create the empty
export with ordinal 0, which makes its behaviour more in line with both
the MSVC linker and the GNU linker.

Reviewed By: mstorsjo

Differential Revision: https://reviews.llvm.org/D134140
This commit is contained in:
Alvin Wong 2022-10-03 10:39:48 +03:00 committed by Martin Storsjö
parent dd9dfb57da
commit e2e132c5d9
15 changed files with 17 additions and 43 deletions

View File

@ -491,8 +491,8 @@ public:
auto *e = (export_directory_table_entry *)(buf);
e->NameRVA = dllName->getRVA();
e->OrdinalBase = 0;
e->AddressTableEntries = maxOrdinal + 1;
e->OrdinalBase = 1;
e->AddressTableEntries = maxOrdinal;
e->NumberOfNamePointers = nameTabSize;
e->ExportAddressTableRVA = addressTab->getRVA();
e->NamePointerRVA = nameTab->getRVA();
@ -509,14 +509,16 @@ public:
class AddressTableChunk : public NonSectionChunk {
public:
explicit AddressTableChunk(size_t maxOrdinal) : size(maxOrdinal + 1) {}
explicit AddressTableChunk(size_t maxOrdinal) : size(maxOrdinal) {}
size_t getSize() const override { return size * 4; }
void writeTo(uint8_t *buf) const override {
memset(buf, 0, getSize());
for (const Export &e : config->exports) {
uint8_t *p = buf + e.ordinal * 4;
assert(e.ordinal != 0 && "Export symbol has invalid ordinal");
// OrdinalBase is 1, so subtract 1 to get the index.
uint8_t *p = buf + (e.ordinal - 1) * 4;
uint32_t bit = 0;
// Pointer to thumb code must have the LSB set, so adjust it.
if (config->machine == ARMNT && !e.data)
@ -560,7 +562,9 @@ public:
for (Export &e : config->exports) {
if (e.noname)
continue;
write16le(buf, e.ordinal);
assert(e.ordinal != 0 && "Export symbol has invalid ordinal");
// This table stores unbiased indices, so subtract 1 (OrdinalBase).
write16le(buf, e.ordinal - 1);
buf += 2;
}
}

View File

@ -8,7 +8,6 @@
# CHECK: Export Table:
# CHECK: DLL name: directives.s.tmp.dll
# CHECK: Ordinal RVA Name
# CHECK-NEXT: 0 0
# CHECK-NEXT: 1 0x1000 exportfn1
# CHECK-NEXT: 2 0x1000 exportfn2
# CHECK-NEXT: 3 0x1000 exportfn3

View File

@ -7,7 +7,6 @@
EXPORT: Export Table:
EXPORT: DLL name: dll.test.tmp.dll
EXPORT: Ordinal RVA Name
EXPORT-NEXT: 0 0
EXPORT-NEXT: 1 0x1008 exportfn1
EXPORT-NEXT: 2 0x1010 exportfn2
EXPORT-NEXT: 3 0x1010 exportfn3
@ -22,7 +21,6 @@ EXPORT-NEXT: 4 0x1010 mangled
EXPORT2: Export Table:
EXPORT2: DLL name: dll.test.tmp5.dll
EXPORT2: Ordinal RVA Name
EXPORT2-NEXT: 0 0
EXPORT2-NEXT: 1 0x1010 exportfn3
EXPORT2-NEXT: 2 0x101c mangled2
@ -33,7 +31,6 @@ EXPORT2-NEXT: 2 0x101c mangled2
EXPORT-LTO: Export Table:
EXPORT-LTO: DLL name: dll.test.tmp.lto.dll
EXPORT-LTO: Ordinal RVA Name
EXPORT-LTO-NEXT: 0 0
EXPORT-LTO-NEXT: 1 0x1010 exportfn1
EXPORT-LTO-NEXT: 2 0x1020 exportfn2
EXPORT-LTO-NEXT: 3 0x1030 exportfn3

View File

@ -4,7 +4,6 @@
// RUN: lld-link -lldmingw -dll -out:%t.dll %t.o -noentry
// RUN: llvm-readobj --coff-exports %t.dll | FileCheck --implicit-check-not=Name: %s
// CHECK: Name:
// CHECK: Name: sym1
.global _sym1

View File

@ -4,7 +4,6 @@
// RUN: lld-link -lldmingw -dll -out:%t.dll %t.o -noentry -exclude-symbols:sym2,unknownsym -exclude-symbols:unknownsym,sym3
// RUN: llvm-readobj --coff-exports %t.dll | FileCheck --implicit-check-not=Name: %s
// CHECK: Name:
// CHECK: Name: sym1
.global _sym1

View File

@ -7,8 +7,8 @@
# RUN: llvm-readobj --coff-exports %t.dll | FileCheck %s --check-prefix=CHECK-RVA
# RUN: llvm-readobj %t.lib | FileCheck -check-prefix=IMPLIB %s
# CHECK: Name:
# CHECK-NEXT: Name: comdatFunc
# CHECK: Name:
# CHECK-SAME: comdatFunc
# CHECK-NEXT: Name: dataSym
# CHECK-NEXT: Name: foobar
# CHECK-EMPTY:

View File

@ -8,7 +8,6 @@
# CHECK: Export Table:
# CHECK: DLL name: export-arm64.yaml.tmp.dll
# CHECK: Ordinal RVA Name
# CHECK-NEXT: 0 0
# CHECK-NEXT: 1 0x1008 exportfn1
# CHECK-NEXT: 2 0x1010 exportfn2
# CHECK-NEXT: 3 0x1018 exportfn3

View File

@ -8,7 +8,6 @@
# CHECK: Export Table:
# CHECK: DLL name: export-armnt.yaml.tmp.dll
# CHECK: Ordinal RVA Name
# CHECK-NEXT: 0 0
# CHECK-NEXT: 1 0x3000 exportdata
# CHECK-NEXT: 2 0x1005 exportfn1
# CHECK-NEXT: 3 0x1009 exportfn2

View File

@ -4,7 +4,6 @@
CHECK: Export Table:
CHECK-NEXT: DLL name: export-exe.test.tmp.exe
CHECK-NEXT: Ordinal base: 0
CHECK-NEXT: Ordinal base: 1
CHECK-NEXT: Ordinal RVA Name
CHECK-NEXT: 0 0
CHECK-NEXT: 1 0x1000 main

View File

@ -6,7 +6,6 @@
CHECK1: Export Table:
CHECK1: DLL name: export.test.tmp.dll
CHECK1: Ordinal RVA Name
CHECK1-NEXT: 0 0
CHECK1-NEXT: 1 0x1008 exportfn1
CHECK1-NEXT: 2 0x1010 exportfn2
@ -16,7 +15,6 @@ CHECK1-NEXT: 2 0x1010 exportfn2
CHECK2: Export Table:
CHECK2: DLL name: export.test.tmp.dll
CHECK2: Ordinal RVA Name
CHECK2-NEXT: 0 0
CHECK2-NEXT: 1 0
CHECK2-NEXT: 2 0
CHECK2-NEXT: 3 0
@ -31,7 +29,6 @@ CHECK2-NEXT: 7 0x1010 exportfn3
CHECK3: Export Table:
CHECK3: DLL name: export.test.tmp.dll
CHECK3: Ordinal RVA Name
CHECK3-NEXT: 0 0
CHECK3-NEXT: 1 0
CHECK3-NEXT: 2 0
CHECK3-NEXT: 3 0
@ -46,7 +43,6 @@ CHECK3-NEXT: 6 0x1010 exportfn2
CHECK4: Export Table:
CHECK4: DLL name: export.test.tmp.dll
CHECK4: Ordinal RVA Name
CHECK4-NEXT: 0 0
CHECK4-NEXT: 1 0x1010 exportfn3
CHECK4-NEXT: 2 0x1008 f1
CHECK4-NEXT: 3 0x1010 f2
@ -61,7 +57,6 @@ CHECK4-NM: 00000000 T f2
CHECK5: Export Table:
CHECK5: DLL name: export.test.tmp.dll
CHECK5: Ordinal RVA Name
CHECK5-NEXT: 0 0
CHECK5-NEXT: 1 0
CHECK5-NEXT: 2 0x1010 fn2
CHECK5-NEXT: 3 0x1008 exportfn1
@ -92,9 +87,8 @@ SYMTAB: exportfn3 in export.test.tmp.DLL
FORWARDER: Export Table:
FORWARDER: DLL name: export.test.tmp.dll
FORWARDER: Ordinal base: 0
FORWARDER: Ordinal base: 1
FORWARDER: Ordinal RVA Name
FORWARDER: 0 0
FORWARDER: 1 0x1010 exportfn
FORWARDER: 2 foo (forwarded to kernel32.foobar)
@ -103,6 +97,5 @@ FORWARDER: 2 foo (forwarded to kernel32.foobar)
MERGE: DLL name: export.test.tmp.dll
MERGE: Ordinal RVA Name
MERGE-NEXT: 0 0
MERGE-NEXT: 1 0x1008 exportfn1
MERGE-NEXT: 2 0x1010 exportfn2

View File

@ -10,14 +10,13 @@
# CHECK1: Export Table:
# CHECK1: DLL name: export32.test.tmp.dll
# CHECK1: Ordinal RVA Name
# CHECK1-NEXT: 0 0
# CHECK1-NEXT: 1 0x1008 exportfn1
# CHECK1-NEXT: 2 0x1010 exportfn2
# HEADER-MERGE: ExportTableRVA: 0x2000
# HEADER-MERGE-NEXT: ExportTableSize: 0x7E
# HEADER-MERGE-NEXT: ExportTableSize: 0x7A
# HEADER-MERGE: Name: .rdata
# HEADER-MERGE-NEXT: VirtualSize: 0x7E
# HEADER-MERGE-NEXT: VirtualSize: 0x7A
# HEADER-MERGE-NEXT: VirtualAddress: 0x2000
# RUN: lld-link -safeseh:no /out:%t.dll /dll %t.obj /export:exportfn1,@5 \
@ -27,7 +26,6 @@
# CHECK2: Export Table:
# CHECK2: DLL name: export32.test.tmp.dll
# CHECK2: Ordinal RVA Name
# CHECK2-NEXT: 0 0
# CHECK2-NEXT: 1 0
# CHECK2-NEXT: 2 0
# CHECK2-NEXT: 3 0
@ -43,7 +41,6 @@
# CHECK3: Export Table:
# CHECK3: DLL name: export32.test.tmp.dll
# CHECK3: Ordinal RVA Name
# CHECK3-NEXT: 0 0
# CHECK3-NEXT: 1 0
# CHECK3-NEXT: 2 0
# CHECK3-NEXT: 3 0
@ -57,7 +54,6 @@
# CHECK4: Export Table:
# CHECK4: DLL name: export32.test.tmp.dll
# CHECK4: Ordinal RVA Name
# CHECK4-NEXT: 0 0
# CHECK4-NEXT: 1 0x1010 exportfn3
# CHECK4-NEXT: 2 0x1008 f1
# CHECK4-NEXT: 3 0x1010 f2
@ -75,7 +71,6 @@
# CHECK5: Export Table:
# CHECK5: DLL name: export32.test.tmp.dll
# CHECK5: Ordinal RVA Name
# CHECK5-NEXT: 0 0
# CHECK5-NEXT: 1 0
# CHECK5-NEXT: 2 0x1010 fn2
# CHECK5-NEXT: 3 0x1008 exportfn1
@ -94,7 +89,6 @@
# CHECK7: Export Table:
# CHECK7: DLL name: export32.test.tmp.dll
# CHECK7: Ordinal RVA Name
# CHECK7-NEXT: 0 0
# CHECK7-NEXT: 1 0
# CHECK7-NEXT: 2 0x1010 foo

View File

@ -9,7 +9,7 @@
# There shouldn't be much xdata, because all three .pdata entries (12 bytes
# each) should use the same .xdata unwind info.
# XDATA: Name: .rdata
# XDATA-NEXT: VirtualSize: 0x73
# XDATA-NEXT: VirtualSize: 0x6F
# XDATA: Name: .pdata
# XDATA-NEXT: VirtualSize: 0x24
# XDATA: Name: .xdata
@ -18,7 +18,7 @@
# WARN: warning: .xdata=.rdata: already merged into .xdata
#
# RDATA: Name: .rdata
# RDATA-NEXT: VirtualSize: 0x7C
# RDATA-NEXT: VirtualSize: 0x78
# RDATA: Name: .pdata
# RDATA-NEXT: VirtualSize: 0x24

View File

@ -13,11 +13,6 @@
# from the import library.
EXPORT: Export {
EXPORT-NEXT: Ordinal: 0
EXPORT-NEXT: Name:
EXPORT-NEXT: RVA: 0x0
EXPORT-NEXT: }
EXPORT-NEXT: Export {
EXPORT-NEXT: Ordinal: 1
EXPORT-NEXT: Name: main
EXPORT-NEXT: RVA: 0x1010

View File

@ -13,10 +13,8 @@
// RUN: llvm-readobj --coff-exports %t-1.dll | FileCheck --implicit-check-not=Name: %s --check-prefix=CHECK-DEFAULT
// RUN: llvm-readobj --coff-exports %t-2.dll | FileCheck --implicit-check-not=Name: %s --check-prefix=CHECK-INCLUDEOPTIONAL
// CHECK-DEFAULT: Name:
// CHECK-DEFAULT: Name: myfunc
// CHECK-INCLUDEOPTIONAL: Name:
// CHECK-INCLUDEOPTIONAL: Name: libfunc
// CHECK-INCLUDEOPTIONAL: Name: myfunc
// CHECK-INCLUDEOPTIONAL: Name: otherlibfunc

View File

@ -6,7 +6,6 @@
; RUN: lld-link -opt:icf -dll -noentry %t.bc -out:%t.dll
; RUN: llvm-readobj --coff-exports %t.dll | FileCheck %s
; CHECK: Export {
; CHECK: Export {
; CHECK: RVA: 0x[[RVA:.*]]
; CHECK: Export {