summaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
authorMartin Storsjo <martin@martin.st>2018-09-18 07:22:01 +0000
committerMartin Storsjo <martin@martin.st>2018-09-18 07:22:01 +0000
commit28107564d68a9d8a79d31b158bb45938efb39b1d (patch)
treeace2c3ecf8235df995ef3ce3e6fef3986fb2ad78 /lld
parent1b95b24eb23325904480633afe305e7f4f1fc1c4 (diff)
[COFF] Add support for delay loading DLLs for ARM64
Differential Revision: https://reviews.llvm.org/D52190
Diffstat (limited to 'lld')
-rw-r--r--lld/COFF/Chunks.cpp6
-rw-r--r--lld/COFF/Chunks.h4
-rw-r--r--lld/COFF/DLL.cpp54
-rw-r--r--lld/test/COFF/arm64-delayimport.yaml91
4 files changed, 152 insertions, 3 deletions
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 5e8ab58ebf0..da5120817bf 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -191,7 +191,7 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
// Interpret the existing immediate value as a byte offset to the
// target symbol, then update the instruction with the immediate as
// the page offset from the current instruction to the target.
-static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) {
+void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) {
uint32_t Orig = read32le(Off);
uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC);
S += Imm;
@@ -205,7 +205,7 @@ static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) {
// Update the immediate field in a AARCH64 ldr, str, and add instruction.
// Optionally limit the range of the written immediate by one or more bits
// (RangeLimit).
-static void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) {
+void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) {
uint32_t Orig = read32le(Off);
Imm += (Orig >> 10) & 0xFFF;
Orig &= ~(0xFFF << 10);
@@ -257,7 +257,7 @@ static void applySecRelLdr(const SectionChunk *Sec, uint8_t *Off,
applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff);
}
-static void applyArm64Branch26(uint8_t *Off, int64_t V) {
+void applyArm64Branch26(uint8_t *Off, int64_t V) {
if (!isInt<28>(V))
error("relocation out of range");
or32(Off, (V & 0x0FFFFFFC) >> 2);
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index 4af5cf7f2cb..688375a6cd3 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -474,6 +474,10 @@ private:
void applyMOV32T(uint8_t *Off, uint32_t V);
void applyBranch24T(uint8_t *Off, int32_t V);
+void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift);
+void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit);
+void applyArm64Branch26(uint8_t *Off, int64_t V);
+
} // namespace coff
} // namespace lld
diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp
index 464abe8e089..8f1692e789d 100644
--- a/lld/COFF/DLL.cpp
+++ b/lld/COFF/DLL.cpp
@@ -230,6 +230,36 @@ static const uint8_t ThunkARM[] = {
0x60, 0x47, // bx ip
};
+static const uint8_t ThunkARM64[] = {
+ 0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_<FUNCNAME>
+ 0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_<FUNCNAME>
+ 0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]!
+ 0xfd, 0x03, 0x00, 0x91, // mov x29, sp
+ 0xe0, 0x07, 0x01, 0xa9, // stp x0, x1, [sp, #16]
+ 0xe2, 0x0f, 0x02, 0xa9, // stp x2, x3, [sp, #32]
+ 0xe4, 0x17, 0x03, 0xa9, // stp x4, x5, [sp, #48]
+ 0xe6, 0x1f, 0x04, 0xa9, // stp x6, x7, [sp, #64]
+ 0xe0, 0x87, 0x02, 0xad, // stp q0, q1, [sp, #80]
+ 0xe2, 0x8f, 0x03, 0xad, // stp q2, q3, [sp, #112]
+ 0xe4, 0x97, 0x04, 0xad, // stp q4, q5, [sp, #144]
+ 0xe6, 0x9f, 0x05, 0xad, // stp q6, q7, [sp, #176]
+ 0xe1, 0x03, 0x11, 0xaa, // mov x1, x17
+ 0x00, 0x00, 0x00, 0x90, // adrp x0, #0 DELAY_IMPORT_DESCRIPTOR
+ 0x00, 0x00, 0x00, 0x91, // add x0, x0, #0 :lo12:DELAY_IMPORT_DESCRIPTOR
+ 0x00, 0x00, 0x00, 0x94, // bl #0 __delayLoadHelper2
+ 0xf0, 0x03, 0x00, 0xaa, // mov x16, x0
+ 0xe6, 0x9f, 0x45, 0xad, // ldp q6, q7, [sp, #176]
+ 0xe4, 0x97, 0x44, 0xad, // ldp q4, q5, [sp, #144]
+ 0xe2, 0x8f, 0x43, 0xad, // ldp q2, q3, [sp, #112]
+ 0xe0, 0x87, 0x42, 0xad, // ldp q0, q1, [sp, #80]
+ 0xe6, 0x1f, 0x44, 0xa9, // ldp x6, x7, [sp, #64]
+ 0xe4, 0x17, 0x43, 0xa9, // ldp x4, x5, [sp, #48]
+ 0xe2, 0x0f, 0x42, 0xa9, // ldp x2, x3, [sp, #32]
+ 0xe0, 0x07, 0x41, 0xa9, // ldp x0, x1, [sp, #16]
+ 0xfd, 0x7b, 0xcd, 0xa8, // ldp x29, x30, [sp], #208
+ 0x00, 0x02, 0x1f, 0xd6, // br x16
+};
+
// A chunk for the delay import thunk.
class ThunkChunkX64 : public Chunk {
public:
@@ -298,6 +328,28 @@ public:
Defined *Helper = nullptr;
};
+class ThunkChunkARM64 : public Chunk {
+public:
+ ThunkChunkARM64(Defined *I, Chunk *D, Defined *H)
+ : Imp(I), Desc(D), Helper(H) {}
+
+ size_t getSize() const override { return sizeof(ThunkARM64); }
+
+ void writeTo(uint8_t *Buf) const override {
+ memcpy(Buf + OutputSectionOff, ThunkARM64, sizeof(ThunkARM64));
+ applyArm64Addr(Buf + OutputSectionOff + 0, Imp->getRVA(), RVA + 0, 12);
+ applyArm64Imm(Buf + OutputSectionOff + 4, Imp->getRVA() & 0xfff, 0);
+ applyArm64Addr(Buf + OutputSectionOff + 52, Desc->getRVA(), RVA + 52, 12);
+ applyArm64Imm(Buf + OutputSectionOff + 56, Desc->getRVA() & 0xfff, 0);
+ applyArm64Branch26(Buf + OutputSectionOff + 60,
+ Helper->getRVA() - RVA - 60);
+ }
+
+ Defined *Imp = nullptr;
+ Chunk *Desc = nullptr;
+ Defined *Helper = nullptr;
+};
+
// A chunk for the import descriptor table.
class DelayAddressChunk : public Chunk {
public:
@@ -555,6 +607,8 @@ Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
return make<ThunkChunkX86>(S, Dir, Helper);
case ARMNT:
return make<ThunkChunkARM>(S, Dir, Helper);
+ case ARM64:
+ return make<ThunkChunkARM64>(S, Dir, Helper);
default:
llvm_unreachable("unsupported machine type");
}
diff --git a/lld/test/COFF/arm64-delayimport.yaml b/lld/test/COFF/arm64-delayimport.yaml
new file mode 100644
index 00000000000..6d3d70564c0
--- /dev/null
+++ b/lld/test/COFF/arm64-delayimport.yaml
@@ -0,0 +1,91 @@
+# REQUIRES: aarch64
+
+# RUN: yaml2obj < %s > %t.obj
+# 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 -d %t.exe | FileCheck %s -check-prefix DISASM
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s -check-prefix IMPORTS
+
+# DISASM: 140001014: 11 00 00 d0 adrp x17, #8192
+# DISASM: 140001018: 31 22 00 91 add x17, x17, #8
+# DISASM: 14000101c: fd 7b b3 a9 stp x29, x30, [sp, #-208]!
+# DISASM: 140001020: fd 03 00 91 mov x29, sp
+# DISASM: 140001024: e0 07 01 a9 stp x0, x1, [sp, #16]
+# DISASM: 140001028: e2 0f 02 a9 stp x2, x3, [sp, #32]
+# DISASM: 14000102c: e4 17 03 a9 stp x4, x5, [sp, #48]
+# DISASM: 140001030: e6 1f 04 a9 stp x6, x7, [sp, #64]
+# DISASM: 140001034: e0 87 02 ad stp q0, q1, [sp, #80]
+# DISASM: 140001038: e2 8f 03 ad stp q2, q3, [sp, #112]
+# DISASM: 14000103c: e4 97 04 ad stp q4, q5, [sp, #144]
+# DISASM: 140001040: e6 9f 05 ad stp q6, q7, [sp, #176]
+# DISASM: 140001044: e1 03 11 aa mov x1, x17
+# DISASM: 140001048: 00 00 00 b0 adrp x0, #4096
+# DISASM: 14000104c: 00 00 00 91 add x0, x0, #0
+# DISASM: 140001050: ec ff ff 97 bl #-80 <.text>
+# DISASM: 140001054: f0 03 00 aa mov x16, x0
+# DISASM: 140001058: e6 9f 45 ad ldp q6, q7, [sp, #176]
+# DISASM: 14000105c: e4 97 44 ad ldp q4, q5, [sp, #144]
+# DISASM: 140001060: e2 8f 43 ad ldp q2, q3, [sp, #112]
+# DISASM: 140001064: e0 87 42 ad ldp q0, q1, [sp, #80]
+# DISASM: 140001068: e6 1f 44 a9 ldp x6, x7, [sp, #64]
+# DISASM: 14000106c: e4 17 43 a9 ldp x4, x5, [sp, #48]
+# DISASM: 140001070: e2 0f 42 a9 ldp x2, x3, [sp, #32]
+# DISASM: 140001074: e0 07 41 a9 ldp x0, x1, [sp, #16]
+# DISASM: 140001078: fd 7b cd a8 ldp x29, x30, [sp], #208
+# DISASM: 14000107c: 00 02 1f d6 br x16
+
+# IMPORTS: Format: COFF-ARM64
+# IMPORTS: Arch: aarch64
+# IMPORTS: AddressSize: 64bit
+# IMPORTS: DelayImport {
+# IMPORTS: Name: library.dll
+# IMPORTS: Attributes: 0x1
+# IMPORTS: ModuleHandle: 0x3000
+# IMPORTS: ImportAddressTable: 0x3008
+# IMPORTS: ImportNameTable: 0x2040
+# IMPORTS: BoundDelayImportTable: 0x0
+# IMPORTS: UnloadDelayImportTable: 0x0
+# IMPORTS: Import {
+# IMPORTS: Symbol: function (0)
+# IMPORTS: Address: 0x140001014
+# IMPORTS: }
+# IMPORTS: }
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_ARM64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 00000094C0035FD6
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: function
+ Type: IMAGE_REL_ARM64_BRANCH26
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: function
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...