Index: lld/trunk/COFF/Chunks.h =================================================================== --- lld/trunk/COFF/Chunks.h +++ lld/trunk/COFF/Chunks.h @@ -369,6 +369,9 @@ uint8_t Type; }; +void applyMOV32T(uint8_t *Off, uint32_t V); +void applyBranch24T(uint8_t *Off, int32_t V); + } // namespace coff } // namespace lld Index: lld/trunk/COFF/Chunks.cpp =================================================================== --- lld/trunk/COFF/Chunks.cpp +++ lld/trunk/COFF/Chunks.cpp @@ -119,7 +119,7 @@ return Imm; } -static void applyMOV32T(uint8_t *Off, uint32_t V) { +void applyMOV32T(uint8_t *Off, uint32_t V) { uint16_t ImmW = readMOV(Off); // read MOVW operand uint16_t ImmT = readMOV(Off + 4); // read MOVT operand uint32_t Imm = ImmW | (ImmT << 16); @@ -136,7 +136,7 @@ or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); } -static void applyBranch24T(uint8_t *Off, int32_t V) { +void applyBranch24T(uint8_t *Off, int32_t V) { if (!isInt<25>(V)) fatal("relocation out of range"); uint32_t S = V < 0 ? 1 : 0; @@ -496,6 +496,7 @@ case AMD64: return IMAGE_REL_BASED_DIR64; case I386: + case ARMNT: return IMAGE_REL_BASED_HIGHLOW; default: llvm_unreachable("unknown machine type"); Index: lld/trunk/COFF/DLL.cpp =================================================================== --- lld/trunk/COFF/DLL.cpp +++ lld/trunk/COFF/DLL.cpp @@ -215,6 +215,22 @@ 0xFF, 0xE0, // jmp eax }; +static const uint8_t ThunkARM[] = { + 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_ + 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_ + 0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr} + 0x0d, 0xf2, 0x10, 0x0b, // addw r11, sp, #16 + 0x2d, 0xed, 0x10, 0x0b, // vpush {d0, d1, d2, d3, d4, d5, d6, d7} + 0x61, 0x46, // mov r1, ip + 0x40, 0xf2, 0x00, 0x00, // mov.w r0, #0 DELAY_IMPORT_DESCRIPTOR + 0xc0, 0xf2, 0x00, 0x00, // mov.t r0, #0 DELAY_IMPORT_DESCRIPTOR + 0x00, 0xf0, 0x00, 0xd0, // bl #0 __delayLoadHelper2 + 0x84, 0x46, // mov ip, r0 + 0xbd, 0xec, 0x10, 0x0b, // vpop {d0, d1, d2, d3, d4, d5, d6, d7} + 0xbd, 0xe8, 0x0f, 0x48, // pop.w {r0, r1, r2, r3, r11, lr} + 0x60, 0x47, // bx ip +}; + // A chunk for the delay import thunk. class ThunkChunkX64 : public Chunk { public: @@ -259,6 +275,30 @@ Defined *Helper = nullptr; }; +class ThunkChunkARM : public Chunk { +public: + ThunkChunkARM(Defined *I, Chunk *D, Defined *H) + : Imp(I), Desc(D), Helper(H) {} + + size_t getSize() const override { return sizeof(ThunkARM); } + + void writeTo(uint8_t *Buf) const override { + memcpy(Buf + OutputSectionOff, ThunkARM, sizeof(ThunkARM)); + applyMOV32T(Buf + OutputSectionOff + 0, Imp->getRVA() + Config->ImageBase); + applyMOV32T(Buf + OutputSectionOff + 22, Desc->getRVA() + Config->ImageBase); + applyBranch24T(Buf + OutputSectionOff + 30, Helper->getRVA() - RVA - 34); + } + + void getBaserels(std::vector *Res) override { + Res->emplace_back(RVA + 0, IMAGE_REL_BASED_ARM_MOV32T); + Res->emplace_back(RVA + 22, IMAGE_REL_BASED_ARM_MOV32T); + } + + Defined *Imp = nullptr; + Chunk *Desc = nullptr; + Defined *Helper = nullptr; +}; + // A chunk for the import descriptor table. class DelayAddressChunk : public Chunk { public: @@ -269,7 +309,11 @@ if (Config->is64()) { write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); } else { - write32le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); + uint32_t Bit = 0; + // Pointer to thumb code must have the LSB set, so adjust it. + if (Config->Machine == ARMNT) + Bit = 1; + write32le(Buf + OutputSectionOff, (Thunk->getRVA() + Config->ImageBase) | Bit); } } @@ -510,6 +554,8 @@ return make(S, Dir, Helper); case I386: return make(S, Dir, Helper); + case ARMNT: + return make(S, Dir, Helper); default: llvm_unreachable("unsupported machine type"); } Index: lld/trunk/test/COFF/delayimports-armnt.yaml =================================================================== --- lld/trunk/test/COFF/delayimports-armnt.yaml +++ lld/trunk/test/COFF/delayimports-armnt.yaml @@ -0,0 +1,106 @@ +# REQUIRES: arm +# RUN: yaml2obj < %s > %t.obj +# RUN: lld-link %t.obj %p/Inputs/library.lib /subsystem:console \ +# RUN: /entry:mainCRTStartup /alternatename:__delayLoadHelper2=mainCRTStartup \ +# RUN: /delayload:library.dll /out:%t.exe +# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s +# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s +# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s + +# IMPORT: Format: COFF-ARM +# IMPORT-NEXT: Arch: thumb +# IMPORT-NEXT: AddressSize: 32bit +# IMPORT-NEXT: DelayImport { +# IMPORT-NEXT: Name: library.dll +# IMPORT-NEXT: Attributes: 0x1 +# IMPORT-NEXT: ModuleHandle: 0x3000 +# IMPORT-NEXT: ImportAddressTable: 0x3008 +# IMPORT-NEXT: ImportNameTable: 0x2040 +# IMPORT-NEXT: BoundDelayImportTable: 0x0 +# IMPORT-NEXT: UnloadDelayImportTable: 0x0 +# IMPORT-NEXT: Import { +# IMPORT-NEXT: Symbol: function (0) +# IMPORT-NEXT: Address: 0x401019 +# IMPORT-NEXT: } +# IMPORT-NEXT: } +# +# BASEREL: BaseReloc [ +# BASEREL-NEXT: Entry { +# BASEREL-NEXT: Type: ARM_MOV32(T) +# BASEREL-NEXT: Address: 0x1000 +# BASEREL-NEXT: } +# BASEREL-NEXT: Entry { +# BASEREL-NEXT: Type: ARM_MOV32(T) +# BASEREL-NEXT: Address: 0x100C +# BASEREL-NEXT: } +# BASEREL-NEXT: Entry { +# BASEREL-NEXT: Type: ARM_MOV32(T) +# BASEREL-NEXT: Address: 0x1018 +# BASEREL-NEXT: } +# BASEREL-NEXT: Entry { +# BASEREL-NEXT: Type: ARM_MOV32(T) +# BASEREL-NEXT: Address: 0x102E +# BASEREL-NEXT: } +# BASEREL-NEXT: Entry { +# BASEREL-NEXT: Type: HIGHLOW +# BASEREL-NEXT: Address: 0x3008 +# BASEREL-NEXT: } +# BASEREL-NEXT: Entry { +# BASEREL-NEXT: Type: ABSOLUTE +# BASEREL-NEXT: Address: 0x3000 +# BASEREL-NEXT: } +# BASEREL-NEXT: ] +# +# DISASM: 401018: 43 f2 08 0c movw r12, #12296 +# DISASM-NEXT: 40101c: c0 f2 40 0c movt r12, #64 +# DISASM-NEXT: 401020: 2d e9 0f 48 push.w {r0, r1, r2, r3, r11, lr} +# DISASM-NEXT: 401024: 0d f2 10 0b addw r11, sp, #16 +# DISASM-NEXT: 401028: 2d ed 10 0b vpush {d0, d1, d2, d3, d4, d5, d6, d7} +# DISASM-NEXT: 40102c: 61 46 mov r1, r12 +# DISASM-NEXT: 40102e: 42 f2 00 00 movw r0, #8192 +# DISASM-NEXT: 401032: c0 f2 40 00 movt r0, #64 +# DISASM-NEXT: 401036: ff f7 e3 ff bl #-58 +# DISASM-NEXT: 40103a: 84 46 mov r12, r0 +# DISASM-NEXT: 40103c: bd ec 10 0b vpop {d0, d1, d2, d3, d4, d5, d6, d7} +# DISASM-NEXT: 401040: bd e8 0f 48 pop.w {r0, r1, r2, r3, r11, lr} +# DISASM-NEXT: 401044: 60 47 bx r12 + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_ARMNT + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 40F20000C0F2000000680047 + Relocations: + - VirtualAddress: 0 + SymbolName: __imp_function + Type: 17 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 1 + - Name: mainCRTStartup + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __imp_function + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +...