-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[LLD][COFF] Add Support for ARM64EC Import Thunks #108460
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
Conversation
Depends on #108459. |
@llvm/pr-subscribers-platform-windows @llvm/pr-subscribers-lld Author: Jacek Caban (cjacek) ChangesARM64EC import thunks function similarly to regular ARM64 thunks but use a mangled name and perform the call through the auxiliary IAT. Full diff: https://github.com/llvm/llvm-project/pull/108460.diff 11 Files Affected:
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 0f33885f7df37d..ee54fa39fc3d6a 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -774,6 +774,10 @@ void StringChunk::writeTo(uint8_t *buf) const {
buf[str.size()] = '\0';
}
+ImportThunkChunk::ImportThunkChunk(COFFLinkerContext &ctx, Defined *s)
+ : NonSectionCodeChunk(ImportThunkKind), live(!ctx.config.doGC),
+ impSymbol(s), ctx(ctx) {}
+
ImportThunkChunkX64::ImportThunkChunkX64(COFFLinkerContext &ctx, Defined *s)
: ImportThunkChunk(ctx, s) {
// Intel Optimization Manual says that all branch targets
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index 040a249aabf59e..24d7c37de7f3b0 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -557,10 +557,13 @@ static const uint8_t importThunkARM64EC[] = {
// contents will be a JMP instruction to some __imp_ symbol.
class ImportThunkChunk : public NonSectionCodeChunk {
public:
- ImportThunkChunk(COFFLinkerContext &ctx, Defined *s)
- : NonSectionCodeChunk(ImportThunkKind), impSymbol(s), ctx(ctx) {}
+ ImportThunkChunk(COFFLinkerContext &ctx, Defined *s);
static bool classof(const Chunk *c) { return c->kind() == ImportThunkKind; }
+ // We track the usage of the thunk symbol separately from the import file
+ // to avoid generating unnecessary thunks.
+ bool live;
+
protected:
Defined *impSymbol;
COFFLinkerContext &ctx;
@@ -598,13 +601,17 @@ class ImportThunkChunkARM : public ImportThunkChunk {
class ImportThunkChunkARM64 : public ImportThunkChunk {
public:
- explicit ImportThunkChunkARM64(COFFLinkerContext &ctx, Defined *s)
- : ImportThunkChunk(ctx, s) {
+ explicit ImportThunkChunkARM64(COFFLinkerContext &ctx, Defined *s,
+ MachineTypes machine)
+ : ImportThunkChunk(ctx, s), machine(machine) {
setAlignment(4);
}
size_t getSize() const override { return sizeof(importThunkARM64); }
void writeTo(uint8_t *buf) const override;
- MachineTypes getMachine() const override { return ARM64; }
+ MachineTypes getMachine() const override { return machine; }
+
+private:
+ MachineTypes machine;
};
// ARM64EC __impchk_* thunk implementation.
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index 569220468e96ad..94ad7f3ceb306a 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -1002,7 +1002,7 @@ void ObjFile::enqueuePdbFile(StringRef path, ObjFile *fromFile) {
}
ImportFile::ImportFile(COFFLinkerContext &ctx, MemoryBufferRef m)
- : InputFile(ctx, ImportKind, m), live(!ctx.config.doGC), thunkLive(live) {}
+ : InputFile(ctx, ImportKind, m), live(!ctx.config.doGC) {}
MachineTypes ImportFile::getMachineType() const {
uint16_t machine =
@@ -1018,7 +1018,7 @@ ImportThunkChunk *ImportFile::makeImportThunk() {
case I386:
return make<ImportThunkChunkX86>(ctx, impSym);
case ARM64:
- return make<ImportThunkChunkARM64>(ctx, impSym);
+ return make<ImportThunkChunkARM64>(ctx, impSym, ARM64);
case ARMNT:
return make<ImportThunkChunkARM>(ctx, impSym);
}
@@ -1109,7 +1109,14 @@ void ImportFile::parse() {
} else {
thunkSym = ctx.symtab.addImportThunk(
name, impSym, make<ImportThunkChunkX64>(ctx, impSym));
- // FIXME: Add aux IAT symbols.
+
+ if (std::optional<std::string> mangledName =
+ getArm64ECMangledFunctionName(name)) {
+ StringRef auxThunkName = saver().save(*mangledName);
+ auxThunkSym = ctx.symtab.addImportThunk(
+ auxThunkName, impECSym,
+ make<ImportThunkChunkARM64>(ctx, impECSym, ARM64EC));
+ }
StringRef impChkName = saver().save("__impchk_" + name);
impchkThunk = make<ImportThunkChunkARM64EC>(this);
diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h
index 8140a031f71166..acf221d85ae8f2 100644
--- a/lld/COFF/InputFiles.h
+++ b/lld/COFF/InputFiles.h
@@ -365,17 +365,15 @@ class ImportFile : public InputFile {
// Auxiliary IAT symbol and chunk on ARM64EC.
DefinedImportData *impECSym = nullptr;
Chunk *auxLocation = nullptr;
+ Symbol *auxThunkSym = nullptr;
// We want to eliminate dllimported symbols if no one actually refers to them.
// These "Live" bits are used to keep track of which import library members
// are actually in use.
//
// If the Live bit is turned off by MarkLive, Writer will ignore dllimported
- // symbols provided by this import library member. We also track whether the
- // imported symbol is used separately from whether the thunk is used in order
- // to avoid creating unnecessary thunks.
+ // symbols provided by this import library member.
bool live;
- bool thunkLive;
};
// Used for LTO.
diff --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp
index ed521dd375ed01..52e9ce996f2390 100644
--- a/lld/COFF/MapFile.cpp
+++ b/lld/COFF/MapFile.cpp
@@ -125,7 +125,7 @@ static void getSymbols(const COFFLinkerContext &ctx,
if (!file->thunkSym)
continue;
- if (!file->thunkLive)
+ if (!file->thunkSym->isLive())
continue;
if (auto *thunkSym = dyn_cast<Defined>(file->thunkSym))
diff --git a/lld/COFF/MarkLive.cpp b/lld/COFF/MarkLive.cpp
index 8af58780e13582..3c09baa73a9f7b 100644
--- a/lld/COFF/MarkLive.cpp
+++ b/lld/COFF/MarkLive.cpp
@@ -58,7 +58,7 @@ void markLive(COFFLinkerContext &ctx) {
addImportFile(sym->file);
} else if (auto *sym = dyn_cast<DefinedImportThunk>(b)) {
addImportFile(sym->wrappedSym->file);
- sym->wrappedSym->file->thunkLive = true;
+ sym->getChunk()->live = true;
}
};
diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp
index c0739b37aeb0f3..9b035f53ef49cf 100644
--- a/lld/COFF/PDB.cpp
+++ b/lld/COFF/PDB.cpp
@@ -1527,8 +1527,8 @@ void PDBLinker::addImportFilesToPDB() {
if (!file->thunkSym)
continue;
- if (!file->thunkLive)
- continue;
+ if (!file->thunkSym->isLive())
+ continue;
std::string dll = StringRef(file->dllName).lower();
llvm::pdb::DbiModuleDescriptorBuilder *&mod = dllToModuleDbi[dll];
diff --git a/lld/COFF/Symbols.cpp b/lld/COFF/Symbols.cpp
index 5f4d797f74a2dd..3fb0aa94e24a98 100644
--- a/lld/COFF/Symbols.cpp
+++ b/lld/COFF/Symbols.cpp
@@ -19,6 +19,7 @@
using namespace llvm;
using namespace llvm::object;
+using namespace llvm::COFF;
using namespace lld::coff;
@@ -84,7 +85,7 @@ bool Symbol::isLive() const {
if (auto *imp = dyn_cast<DefinedImportData>(this))
return imp->file->live;
if (auto *imp = dyn_cast<DefinedImportThunk>(this))
- return imp->wrappedSym->file->thunkLive;
+ return imp->getChunk()->live;
// Assume any other kind of symbol is live.
return true;
}
diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h
index 2df60a01ec813d..9b21e09bf83a42 100644
--- a/lld/COFF/Symbols.h
+++ b/lld/COFF/Symbols.h
@@ -395,12 +395,12 @@ class DefinedImportThunk : public Defined {
}
uint64_t getRVA() { return data->getRVA(); }
- Chunk *getChunk() { return data; }
+ ImportThunkChunk *getChunk() const { return data; }
DefinedImportData *wrappedSym;
private:
- Chunk *data;
+ ImportThunkChunk *data;
};
// If you have a symbol "foo" in your object file, a symbol name
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 9a8040008e73ca..216db652c10aa8 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1252,14 +1252,22 @@ void Writer::appendImportThunks() {
if (!file->live)
continue;
- if (!file->thunkSym)
- continue;
+ if (file->thunkSym) {
+ if (!isa<DefinedImportThunk>(file->thunkSym))
+ fatal(toString(ctx, *file->thunkSym) + " was replaced");
+ auto *chunk = cast<DefinedImportThunk>(file->thunkSym)->getChunk();
+ if (chunk->live)
+ textSec->addChunk(chunk);
+ }
+
+ if (file->auxThunkSym) {
+ if (!isa<DefinedImportThunk>(file->auxThunkSym))
+ fatal(toString(ctx, *file->auxThunkSym) + " was replaced");
+ auto *chunk = cast<DefinedImportThunk>(file->auxThunkSym)->getChunk();
+ if (chunk->live)
+ textSec->addChunk(chunk);
+ }
- if (!isa<DefinedImportThunk>(file->thunkSym))
- fatal(toString(ctx, *file->thunkSym) + " was replaced");
- DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym);
- if (file->thunkLive)
- textSec->addChunk(thunk->getChunk());
if (file->impchkThunk)
textSec->addChunk(file->impchkThunk);
}
diff --git a/lld/test/COFF/arm64ec-import.test b/lld/test/COFF/arm64ec-import.test
index f8279cefc3bcfb..e403daa41f368c 100644
--- a/lld/test/COFF/arm64ec-import.test
+++ b/lld/test/COFF/arm64ec-import.test
@@ -39,25 +39,31 @@ RUN: llvm-objdump -d out2.dll | FileCheck --check-prefix=DISASM %s
DISASM: 180001000: 52800000 mov w0, #0x0 // =0
DISASM-NEXT: 180001004: d65f03c0 ret
-DISASM-NEXT: 180001008: d000000b adrp x11, 0x180003000
-DISASM-NEXT: 18000100c: f940056b ldr x11, [x11, #0x8]
-DISASM-NEXT: 180001010: 9000000a adrp x10, 0x180001000 <.text>
-DISASM-NEXT: 180001014: 9101114a add x10, x10, #0x44
-DISASM-NEXT: 180001018: 17fffffa b 0x180001000 <.text>
-DISASM-NEXT: 18000101c: d000000b adrp x11, 0x180003000
-DISASM-NEXT: 180001020: f940096b ldr x11, [x11, #0x10]
-DISASM-NEXT: 180001024: f0ffffea adrp x10, 0x180000000
-DISASM-NEXT: 180001028: 9100014a add x10, x10, #0x0
-DISASM-NEXT: 18000102c: 17fffff5 b 0x180001000 <.text>
-DISASM-NEXT: 180001030: d000000b adrp x11, 0x180003000
-DISASM-NEXT: 180001034: f940116b ldr x11, [x11, #0x20]
-DISASM-NEXT: 180001038: 9000000a adrp x10, 0x180001000 <.text>
-DISASM-NEXT: 18000103c: 9101314a add x10, x10, #0x4c
-DISASM-NEXT: 180001040: 17fffff0 b 0x180001000 <.text>
-DISASM-NEXT: 180001044: 52800020 mov w0, #0x1 // =1
-DISASM-NEXT: 180001048: d65f03c0 ret
-DISASM-NEXT: 18000104c: 52800040 mov w0, #0x2 // =2
-DISASM-NEXT: 180001050: d65f03c0 ret
+DISASM-NEXT: 180001008: 90000030 adrp x16, 0x180005000
+DISASM-NEXT: 18000100c: f9400610 ldr x16, [x16, #0x8]
+DISASM-NEXT: 180001010: d61f0200 br x16
+DISASM-NEXT: 180001014: d000000b adrp x11, 0x180003000
+DISASM-NEXT: 180001018: f940056b ldr x11, [x11, #0x8]
+DISASM-NEXT: 18000101c: 9000000a adrp x10, 0x180001000 <.text>
+DISASM-NEXT: 180001020: 9101714a add x10, x10, #0x5c
+DISASM-NEXT: 180001024: 17fffff7 b 0x180001000 <.text>
+DISASM-NEXT: 180001028: d000000b adrp x11, 0x180003000
+DISASM-NEXT: 18000102c: f940096b ldr x11, [x11, #0x10]
+DISASM-NEXT: 180001030: f0ffffea adrp x10, 0x180000000
+DISASM-NEXT: 180001034: 9100014a add x10, x10, #0x0
+DISASM-NEXT: 180001038: 17fffff2 b 0x180001000 <.text>
+DISASM-NEXT: 18000103c: 90000030 adrp x16, 0x180005000
+DISASM-NEXT: 180001040: f9401210 ldr x16, [x16, #0x20]
+DISASM-NEXT: 180001044: d61f0200 br x16
+DISASM-NEXT: 180001048: d000000b adrp x11, 0x180003000
+DISASM-NEXT: 18000104c: f940116b ldr x11, [x11, #0x20]
+DISASM-NEXT: 180001050: 9000000a adrp x10, 0x180001000 <.text>
+DISASM-NEXT: 180001054: 9101914a add x10, x10, #0x64
+DISASM-NEXT: 180001058: 17ffffea b 0x180001000 <.text>
+DISASM-NEXT: 18000105c: 52800020 mov w0, #0x1 // =1
+DISASM-NEXT: 180001060: d65f03c0 ret
+DISASM-NEXT: 180001064: 52800040 mov w0, #0x2 // =2
+DISASM-NEXT: 180001068: d65f03c0 ret
DISASM-NEXT: ...
DISASM-NEXT: 180002000: ff 25 02 10 00 00 jmpq *0x1002(%rip) # 0x180003008
@@ -65,7 +71,8 @@ RUN: llvm-readobj --hex-dump=.test out.dll | FileCheck --check-prefix=TESTSEC %s
RUN: llvm-readobj --hex-dump=.test out2.dll | FileCheck --check-prefix=TESTSEC %s
TESTSEC: 0x180007000 08500000 00300000 10500000 20500000
TESTSEC-NEXT: 0x180007010 08300000 00500000 10300000 20300000
-TESTSEC-NEXT: 0x180007020 08100000 1c100000 00200000
+TESTSEC-NEXT: 0x180007020 14100000 28100000 00200000 08100000
+TESTSEC-NEXT: 0x180007030 3c100000
RUN: llvm-readobj --headers out.dll | FileCheck -check-prefix=HEADERS %s
HEADERS: LoadConfigTableRVA: 0x4010
@@ -76,9 +83,9 @@ RUN: llvm-readobj --coff-load-config out.dll | FileCheck -check-prefix=LOADCONFI
LOADCONFIG: AuxiliaryIAT: 0x5000
RUN: llvm-readobj --hex-dump=.rdata out.dll | FileCheck -check-prefix=RDATA %s
-RDATA: 0x180005000 00000000 00000000 08100080 01000000
-RDATA-NEXT: 0x180005010 1c100080 01000000 00000000 00000000
-RDATA-NEXT: 0x180005020 30100080 01000000 00000000 00000000
+RDATA: 0x180005000 00000000 00000000 14100080 01000000
+RDATA-NEXT: 0x180005010 28100080 01000000 00000000 00000000
+RDATA-NEXT: 0x180005020 48100080 01000000 00000000 00000000
RUN: llvm-readobj --coff-basereloc out.dll | FileCheck -check-prefix=BASERELOC %s
BASERELOC: BaseReloc [
@@ -110,6 +117,8 @@ arm64ec_data_sym:
.rva __impchk_func
.rva __impchk_func2
.rva func
+ .rva "#func"
+ .rva "#t2func"
#--- icall.s
.text
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
lld/COFF/Symbols.cpp
Outdated
@@ -19,6 +19,7 @@ | |||
|
|||
using namespace llvm; | |||
using namespace llvm::object; | |||
using namespace llvm::COFF; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a stray change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I removed that and merged, thanks!
DISASM-NEXT: 180001050: d65f03c0 ret | ||
DISASM-NEXT: 180001008: 90000030 adrp x16, 0x180005000 | ||
DISASM-NEXT: 18000100c: f9400610 ldr x16, [x16, #0x8] | ||
DISASM-NEXT: 180001010: d61f0200 br x16 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the existing thunks use x11/x10, but these ones uses x16 like they used to, for regular arm64. I had to check, but x16 does indeed seem to be kosher to use on arm64ec.
ARM64EC import thunks function similarly to regular ARM64 thunks but use a mangled name and perform the call through the auxiliary IAT.
078cc03
to
805267a
Compare
ARM64EC import thunks function similarly to regular ARM64 thunks but use a mangled name and perform the call through the auxiliary IAT.