Skip to content

[LLD][COFF] Move delay IAT into its own .didat section. #137100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions lld/COFF/DLL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ void IdataContents::create(COFFLinkerContext &ctx) {
dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry), 4));
}

std::vector<Chunk *> DelayLoadContents::getChunks() {
std::vector<Chunk *> DelayLoadContents::getRDataChunks() {
std::vector<Chunk *> v;
v.insert(v.end(), dirs.begin(), dirs.end());
v.insert(v.end(), names.begin(), names.end());
Expand All @@ -900,13 +900,6 @@ std::vector<Chunk *> DelayLoadContents::getChunks() {
return v;
}

std::vector<Chunk *> DelayLoadContents::getDataChunks() {
std::vector<Chunk *> v;
v.insert(v.end(), moduleHandles.begin(), moduleHandles.end());
v.insert(v.end(), addresses.begin(), addresses.end());
return v;
}

uint64_t DelayLoadContents::getDirSize() {
return dirs.size() * sizeof(delay_import_directory_table_entry);
}
Expand Down
5 changes: 3 additions & 2 deletions lld/COFF/DLL.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ class DelayLoadContents {
void add(DefinedImportData *sym) { imports.push_back(sym); }
bool empty() { return imports.empty(); }
void create();
std::vector<Chunk *> getChunks();
std::vector<Chunk *> getDataChunks();
ArrayRef<Chunk *> getChunks() { return addresses; }
std::vector<Chunk *> getRDataChunks();
ArrayRef<Chunk *> getDataChunks() { return moduleHandles; }
ArrayRef<Chunk *> getCodeChunks() { return thunks; }
ArrayRef<Chunk *> getCodePData() { return pdata; }
ArrayRef<Chunk *> getCodeUnwindInfo() { return unwindinfo; }
Expand Down
1 change: 0 additions & 1 deletion lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2015,7 +2015,6 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Add default section merging rules after user rules. User rules take
// precedence, but we will emit a warning if there is a conflict.
parseMerge(".idata=.rdata");
parseMerge(".didat=.rdata");
parseMerge(".edata=.rdata");
parseMerge(".xdata=.rdata");
parseMerge(".00cfg=.rdata");
Expand Down
4 changes: 3 additions & 1 deletion lld/COFF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1083,7 +1083,7 @@ void Writer::createSections() {
pdataSec = createSection(".pdata", data | r);
idataSec = createSection(".idata", data | r);
edataSec = createSection(".edata", data | r);
didatSec = createSection(".didat", data | r);
didatSec = createSection(".didat", data | r | w);
Copy link
Contributor Author

@jeremyd2019 jeremyd2019 Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MSVC dloadsup.h sayeth:

           // This delay load helper module does not support merging the delay
           // load section to a read only section because memory management
           // would not guarantee that there is commit available - and thus a
           // low memory failure path where the delay load failure hook could
           // not be safely invoked (the delay load section would still be
           // read only) might be encountered.
           //
           // It is a build time configuration problem to produce such a
           // binary so abort here and now so that the problem can be
           // identified & fixed.

Additionally, making this section read-only by default would make such a binary incompatible with OS versions that have ResolveDelayLoadedAPI and don't support IMAGE_GUARD_PROTECT_DELAYLOAD_IAT - they wouldn't know to make the section read-write before writing to it (I know Wine is such a situation).

if (isArm64EC(ctx.config.machine))
a64xrmSec = createSection(".a64xrm", data | r);
rsrcSec = createSection(".rsrc", data | r);
Expand Down Expand Up @@ -1329,6 +1329,8 @@ void Writer::appendImportThunks() {
delayIdata.create();
for (Chunk *c : delayIdata.getChunks())
didatSec->addChunk(c);
for (Chunk *c : delayIdata.getRDataChunks())
rdataSec->addChunk(c);
for (Chunk *c : delayIdata.getDataChunks())
dataSec->addChunk(c);
for (Chunk *c : delayIdata.getCodeChunks())
Expand Down
22 changes: 19 additions & 3 deletions lld/test/COFF/arm64-delayimport.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj %p/Inputs/library-arm64.lib /alternatename:__delayLoadHelper2=main /delayload:library.dll
# RUN: llvm-objdump --no-print-imm-hex -d %t.exe | FileCheck %s --check-prefix DISASM
# RUN: llvm-readobj --coff-imports %t.exe | FileCheck %s -check-prefix IMPORTS
# RUN: llvm-readobj --section-headers %t.exe | FileCheck %s -check-prefix SECTION

# DISASM: 140001014: d0000011 adrp x17, 0x140003000
# DISASM: 140001018: 91002231 add x17, x17, #8
# DISASM: 140001014: f0000011 adrp x17, 0x140004000
# DISASM: 140001018: 91000231 add x17, x17, #0
# DISASM: 14000101c: 14000001 b 0x140001020 <.text+0x20>
# DISASM: 140001020: a9b37bfd stp x29, x30, [sp, #-208]!
# DISASM: 140001024: 910003fd mov x29, sp
Expand Down Expand Up @@ -41,7 +42,7 @@
# IMPORTS: Name: library.dll
# IMPORTS: Attributes: 0x1
# IMPORTS: ModuleHandle: 0x3000
# IMPORTS: ImportAddressTable: 0x3008
# IMPORTS: ImportAddressTable: 0x4000
# IMPORTS: ImportNameTable: 0x2040
# IMPORTS: BoundDelayImportTable: 0x0
# IMPORTS: UnloadDelayImportTable: 0x0
Expand All @@ -50,6 +51,21 @@
# IMPORTS: Address: 0x140001014
# IMPORTS: }
# IMPORTS: }
# SECTION: Name: .didat (2E 64 69 64 61 74 00 00)
# SECTION-NEXT: VirtualSize: 0x10
# SECTION-NEXT: VirtualAddress: 0x4000
# SECTION-NEXT: RawDataSize: 512
# SECTION-NEXT: PointerToRawData: 0x{{[0-9A-F]+}}
# SECTION-NEXT: PointerToRelocations: 0x0
# SECTION-NEXT: PointerToLineNumbers: 0x0
# SECTION-NEXT: RelocationCount: 0
# SECTION-NEXT: LineNumberCount: 0
# SECTION-NEXT: Characteristics [ (0xC0000040)
# SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
# SECTION-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
# SECTION-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000)
# SECTION-NEXT: ]
# SECTION-NEXT: }

--- !COFF
header:
Expand Down
50 changes: 25 additions & 25 deletions lld/test/COFF/arm64ec-delayimport.test
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ RUN: lld-link -machine:arm64ec -dll -noentry -out:out.dll loadconfig-arm64ec.obj
RUN: helper-mangled.obj test-arm64ec.lib test2-arm64ec.lib -delayload:test.dll -map

RUN: llvm-readobj --hex-dump=.test out.dll | FileCheck --check-prefix=TESTSEC %s
TESTSEC: 0x18000a000 00600000 88700000 00200000 10100000
TESTSEC-NEXT: 0x18000a010 08600000 90700000 10200000 30100000
TESTSEC-NEXT: 0x18000a020 1c100000 3c100000 00300000
TESTSEC: 0x18000b000 00600000 00900000 00200000 10100000
TESTSEC-NEXT: 0x18000b010 08600000 08900000 10200000 30100000
TESTSEC-NEXT: 0x18000b020 1c100000 3c100000 00300000

RUN: llvm-objdump -d out.dll | FileCheck --check-prefix=DISASM %s
DISASM: 0000000180001000 <.text>:
Expand All @@ -25,16 +25,16 @@ DISASM-NEXT: 18000100c: d65f03c0 ret
DISASM-NEXT: 180001010: b0000030 adrp x16, 0x180006000
DISASM-NEXT: 180001014: f9400210 ldr x16, [x16]
DISASM-NEXT: 180001018: d61f0200 br x16
DISASM-NEXT: 18000101c: d000002b adrp x11, 0x180007000
DISASM-NEXT: 180001020: f940456b ldr x11, [x11, #0x88]
DISASM-NEXT: 18000101c: 9000004b adrp x11, 0x180009000
DISASM-NEXT: 180001020: f940016b ldr x11, [x11]
DISASM-NEXT: 180001024: 9000000a adrp x10, 0x180001000 <.text>
DISASM-NEXT: 180001028: 9101414a add x10, x10, #0x50
DISASM-NEXT: 18000102c: 17fffff5 b 0x180001000 <.text>
DISASM-NEXT: 180001030: b0000030 adrp x16, 0x180006000
DISASM-NEXT: 180001034: f9400610 ldr x16, [x16, #0x8]
DISASM-NEXT: 180001038: d61f0200 br x16
DISASM-NEXT: 18000103c: d000002b adrp x11, 0x180007000
DISASM-NEXT: 180001040: f940496b ldr x11, [x11, #0x90]
DISASM-NEXT: 18000103c: 9000004b adrp x11, 0x180009000
DISASM-NEXT: 180001040: f940056b ldr x11, [x11, #0x8]
DISASM-NEXT: 180001044: 9000000a adrp x10, 0x180001000 <.text>
DISASM-NEXT: 180001048: 9101614a add x10, x10, #0x58
DISASM-NEXT: 18000104c: 17ffffed b 0x180001000 <.text>
Expand All @@ -43,13 +43,13 @@ DISASM-NEXT: 180001054: d65f03c0 ret
DISASM-NEXT: 180001058: 52800060 mov w0, #0x3 // =3
DISASM-NEXT: 18000105c: d65f03c0 ret
DISASM-NEXT: ...
DISASM-NEXT: 180002000: ff 25 82 50 00 00 jmpq *0x5082(%rip) # 0x180007088
DISASM-NEXT: 180002000: ff 25 fa 6f 00 00 jmpq *0x6ffa(%rip) # 0x180009000
DISASM-NEXT: ...
DISASM-NEXT: 18000200e: 00 00 addb %al, (%rax)
DISASM-NEXT: 180002010: ff 25 7a 50 00 00 jmpq *0x507a(%rip) # 0x180007090
DISASM-NEXT: 180002016: 48 8d 05 6b 50 00 00 leaq 0x506b(%rip), %rax # 0x180007088
DISASM-NEXT: 180002010: ff 25 f2 6f 00 00 jmpq *0x6ff2(%rip) # 0x180009008
DISASM-NEXT: 180002016: 48 8d 05 e3 6f 00 00 leaq 0x6fe3(%rip), %rax # 0x180009000
DISASM-NEXT: 18000201d: e9 0c 00 00 00 jmp 0x18000202e <.text+0x102e>
DISASM-NEXT: 180002022: 48 8d 05 67 50 00 00 leaq 0x5067(%rip), %rax # 0x180007090
DISASM-NEXT: 180002022: 48 8d 05 df 6f 00 00 leaq 0x6fdf(%rip), %rax # 0x180009008
DISASM-NEXT: 180002029: e9 00 00 00 00 jmp 0x18000202e <.text+0x102e>
DISASM-NEXT: 18000202e: 51 pushq %rcx
DISASM-NEXT: 18000202f: 52 pushq %rdx
Expand All @@ -61,7 +61,7 @@ DISASM-NEXT: 18000203d: 66 0f 7f 4c 24 10 movdqa %xmm1, 0x10(%rsp)
DISASM-NEXT: 180002043: 66 0f 7f 54 24 20 movdqa %xmm2, 0x20(%rsp)
DISASM-NEXT: 180002049: 66 0f 7f 5c 24 30 movdqa %xmm3, 0x30(%rsp)
DISASM-NEXT: 18000204f: 48 8b d0 movq %rax, %rdx
DISASM-NEXT: 180002052: 48 8d 0d a7 21 00 00 leaq 0x21a7(%rip), %rcx # 0x180004200
DISASM-NEXT: 180002052: 48 8d 0d a7 1f 00 00 leaq 0x1fa7(%rip), %rcx # 0x180004000
DISASM-NEXT: 180002059: e8 aa ef ff ff callq 0x180001008 <.text+0x8>
DISASM-NEXT: 18000205e: 66 0f 6f 04 24 movdqa (%rsp), %xmm0
DISASM-NEXT: 180002063: 66 0f 6f 4c 24 10 movdqa 0x10(%rsp), %xmm1
Expand All @@ -77,15 +77,15 @@ DISASM-NEXT: 18000207f: ff e0 jmpq *%rax
RUN: llvm-readobj --coff-load-config out.dll | FileCheck --check-prefix=LOADCFG %s
LOADCFG: CHPEMetadata [
LOADCFG: AuxiliaryDelayloadIAT: 0x6000
LOADCFG-NEXT: AuxiliaryDelayloadIATCopy: 0x4000
LOADCFG-NEXT: AuxiliaryDelayloadIATCopy: 0x4078

RUN: llvm-readobj --coff-imports out.dll | FileCheck --check-prefix=IMPORTS %s
IMPORTS: DelayImport {
IMPORTS-NEXT: Name: test.dll
IMPORTS-NEXT: Attributes: 0x1
IMPORTS-NEXT: ModuleHandle: 0x7080
IMPORTS-NEXT: ImportAddressTable: 0x7088
IMPORTS-NEXT: ImportNameTable: 0x4240
IMPORTS-NEXT: ImportAddressTable: 0x9000
IMPORTS-NEXT: ImportNameTable: 0x4040
IMPORTS-NEXT: BoundDelayImportTable: 0x0
IMPORTS-NEXT: UnloadDelayImportTable: 0x0
IMPORTS-NEXT: Import {
Expand All @@ -109,29 +109,29 @@ MAP-NEXT: 0001:00000058 func2_exit_thunk 0000000180001058 t
MAP-NEXT: 0001:00001000 func 0000000180002000 test-arm64ec:test.dll
MAP-NEXT: 0001:00001010 func2 0000000180002010 test-arm64ec:test.dll
MAP-NEXT: 0002:00000000 __imp_data 0000000180003000 test2-arm64ec:test2.dll
MAP-NEXT: 0000:00000000 __hybrid_auxiliary_delayload_iat_copy 0000000180004000 <linker-defined>
MAP-NEXT: 0002:00001000 __auximpcopy_func 0000000180004000 test-arm64ec:test.dll
MAP-NEXT: 0002:00001008 __auximpcopy_func2 0000000180004008 test-arm64ec:test.dll
MAP-NEXT: 0000:00000000 __hybrid_auxiliary_delayload_iat_copy 0000000180004078 <linker-defined>
MAP-NEXT: 0002:00001078 __auximpcopy_func 0000000180004078 test-arm64ec:test.dll
MAP-NEXT: 0002:00001080 __auximpcopy_func2 0000000180004080 test-arm64ec:test.dll
MAP: 0002:00003000 __imp_func 0000000180006000 test-arm64ec:test.dll
MAP-NEXT: 0002:00003008 __imp_func2 0000000180006008 test-arm64ec:test.dll
MAP: 0003:00000088 __imp_aux_func 0000000180007088 test-arm64ec:test.dll
MAP-NEXT: 0003:00000090 __imp_aux_func2 0000000180007090 test-arm64ec:test.dll
MAP: 0005:00000000 __imp_aux_func 0000000180009000 test-arm64ec:test.dll
MAP-NEXT: 0005:00000008 __imp_aux_func2 0000000180009008 test-arm64ec:test.dll

RUN: llvm-readobj --hex-dump=.rdata out.dll | FileCheck --check-prefix=RDATA %s
RDATA: 0x180004000 1c100080 01000000 3c100080 01000000
RDATA-NEXT: 0x180004010 00000000 00000000
RDATA: 0x180004070 {{[0-9a-f]{8} [0-9a-f]{8} }}1c100080 01000000
RDATA-NEXT: 0x180004080 3c100080 01000000 00000000 00000000
RDATA: 0x180006000 1c100080 01000000 3c100080 01000000
RDATA-NEXT: 0x180006010 00000000 00000000

RUN: llvm-readobj --coff-basereloc out.dll | FileCheck --check-prefix=RELOC %s
RELOC: BaseReloc [
RELOC-NEXT: Entry {
RELOC-NEXT: Type: DIR64
RELOC-NEXT: Address: 0x4000
RELOC-NEXT: Address: 0x4078
RELOC-NEXT: }
RELOC-NEXT: Entry {
RELOC-NEXT: Type: DIR64
RELOC-NEXT: Address: 0x4008
RELOC-NEXT: Address: 0x4080
RELOC-NEXT: }
RELOC: Address: 0x6000
RELOC-NEXT: }
Expand All @@ -141,7 +141,7 @@ RELOC-NEXT: Address: 0x6008
RELOC-NEXT: }

RUN: llvm-readobj --hex-dump=.pdata out.dll | FileCheck --check-prefix=PDATA %s
PDATA: 0x180008000 2e200000 81200000 18400000
PDATA: 0x180008000 2e200000 81200000 90400000

Verify that a demangled version of __delayLoadHelper2 can be used.

Expand Down
Loading
Loading