Skip to content

Commit dec0781

Browse files
authored
[LLD][COFF] Always locate the IAT at the beginning of the .rdata section and align its size to 4KB on ARM64EC. (#107588)
This mimics the behavior of MSVC's link.exe. My guess is that the reason for this approach is to facilitate tracking runtime IAT modifications. An auxiliary IAT allows bypassing the call checker for imported function calls. It's the OS's responsibility to ensure that, if runtime patching occurs, the auxiliary IAT is reverted to enable call checking. Modifying the IAT is a form of runtime patching, and ensuring that it doesn’t share pages with other data likely helps with tracking accuracy. Although alignment alone should ensure that the IAT occupies its own pages, placing it at the beginning of the .rdata section might be an optimization. This way, padding is only needed after the IAT, not before. The auxiliary IAT seems to follow a similar idea but is positioned at the end of the .rdata section.
1 parent 4ea6552 commit dec0781

File tree

2 files changed

+39
-5
lines changed

2 files changed

+39
-5
lines changed

lld/COFF/Writer.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ class Writer {
217217
void createExportTable();
218218
void mergeSections();
219219
void sortECChunks();
220+
void appendECImportTables();
220221
void removeUnusedSections();
221222
void assignAddresses();
222223
bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin,
@@ -753,6 +754,7 @@ void Writer::run() {
753754
createExportTable();
754755
mergeSections();
755756
sortECChunks();
757+
appendECImportTables();
756758
removeUnusedSections();
757759
finalizeAddresses();
758760
removeEmptySections();
@@ -914,6 +916,28 @@ void Writer::addSyntheticIdata() {
914916
add(".idata$7", idata.dllNames);
915917
}
916918

919+
void Writer::appendECImportTables() {
920+
if (!isArm64EC(ctx.config.machine))
921+
return;
922+
923+
const uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
924+
925+
// IAT is always placed at the begining of .rdata section and its size
926+
// is aligned to 4KB. Insert it here, after all merges all done.
927+
if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) {
928+
if (!rdataSec->chunks.empty())
929+
rdataSec->chunks.front()->setAlignment(
930+
std::max(0x1000u, rdataSec->chunks.front()->getAlignment()));
931+
iatSize = alignTo(iatSize, 0x1000);
932+
933+
rdataSec->chunks.insert(rdataSec->chunks.begin(),
934+
importAddresses->chunks.begin(),
935+
importAddresses->chunks.end());
936+
rdataSec->contribSections.insert(rdataSec->contribSections.begin(),
937+
importAddresses);
938+
}
939+
}
940+
917941
// Locate the first Chunk and size of the import directory list and the
918942
// IAT.
919943
void Writer::locateImportTables() {
@@ -1069,6 +1093,11 @@ void Writer::createSections() {
10691093
sortCRTSectionChunks(pSec->chunks);
10701094
}
10711095

1096+
// ARM64EC has specific placement and alignment requirements for the IAT.
1097+
// Delay adding its chunks until appendECImportTables.
1098+
if (isArm64EC(ctx.config.machine) && pSec->name == ".idata$5")
1099+
continue;
1100+
10721101
OutputSection *sec = createSection(name, outChars);
10731102
for (Chunk *c : pSec->chunks)
10741103
sec->addChunk(c);

lld/test/COFF/arm64ec-import.test

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,33 @@ RUN: llvm-readobj --coff-imports out2.dll | FileCheck --check-prefix=IMPORTS %s
2020
IMPORTS: Import {
2121
IMPORTS-NEXT: Name: test.dll
2222
IMPORTS-NEXT: ImportLookupTableRVA:
23-
IMPORTS-NEXT: ImportAddressTableRVA: 0x2258
23+
IMPORTS-NEXT: ImportAddressTableRVA: 0x2000
2424
IMPORTS-NEXT: Symbol: data (0)
2525
IMPORTS-NEXT: Symbol: func (0)
2626
IMPORTS-NEXT: Symbol: func2 (0)
2727
IMPORTS-NEXT: }
2828
IMPORTS-NEXT: Import {
2929
IMPORTS-NEXT: Name: test2.dll
3030
IMPORTS-NEXT: ImportLookupTableRVA:
31-
IMPORTS-NEXT: ImportAddressTableRVA: 0x2278
31+
IMPORTS-NEXT: ImportAddressTableRVA: 0x2020
3232
IMPORTS-NEXT: Symbol: t2func (0)
3333
IMPORTS-NEXT: }
3434

3535
RUN: llvm-objdump -d out.dll | FileCheck --check-prefix=DISASM %s
3636
RUN: llvm-objdump -d out2.dll | FileCheck --check-prefix=DISASM %s
3737

3838
DISASM: 0000000180001000 <.text>:
39-
DISASM-NEXT: 180001000: ff 25 5a 12 00 00 jmpq *0x125a(%rip) # 0x180002260
39+
DISASM-NEXT: 180001000: ff 25 02 10 00 00 jmpq *0x1002(%rip) # 0x180002008
4040

4141
RUN: llvm-readobj --hex-dump=.test out.dll | FileCheck --check-prefix=TESTSEC %s
4242
RUN: llvm-readobj --hex-dump=.test out2.dll | FileCheck --check-prefix=TESTSEC %s
43-
TESTSEC: 0x180004000 60220000 58220000 68220000 78220000
44-
TESTSEC-NEXT: 0x180004010 00100000
43+
TESTSEC: 0x180005000 08200000 00200000 10200000 20200000
44+
TESTSEC-NEXT: 0x180005010 00100000
45+
46+
RUN: llvm-readobj --headers out.dll | FileCheck -check-prefix=HEADERS %s
47+
HEADERS: LoadConfigTableRVA: 0x3008
48+
HEADERS: IATRVA: 0x2000
49+
HEADERS: IATSize: 0x1000
4550

4651
#--- test.s
4752
.section .test, "r"

0 commit comments

Comments
 (0)