Index: lld/trunk/COFF/Chunks.h =================================================================== --- lld/trunk/COFF/Chunks.h +++ lld/trunk/COFF/Chunks.h @@ -474,6 +474,10 @@ 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 Index: lld/trunk/COFF/Chunks.cpp =================================================================== --- lld/trunk/COFF/Chunks.cpp +++ lld/trunk/COFF/Chunks.cpp @@ -191,7 +191,7 @@ // 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 @@ // 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 @@ 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); Index: lld/trunk/COFF/DLL.cpp =================================================================== --- lld/trunk/COFF/DLL.cpp +++ lld/trunk/COFF/DLL.cpp @@ -230,6 +230,36 @@ 0x60, 0x47, // bx ip }; +static const uint8_t ThunkARM64[] = { + 0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_ + 0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_ + 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 @@ 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 @@ return make(S, Dir, Helper); case ARMNT: return make(S, Dir, Helper); + case ARM64: + return make(S, Dir, Helper); default: llvm_unreachable("unsupported machine type"); } Index: lld/trunk/test/COFF/arm64-delayimport.yaml =================================================================== --- lld/trunk/test/COFF/arm64-delayimport.yaml +++ lld/trunk/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 +...