[COFF] Add support for delay loading DLLs on ARM

Differential Revision: https://reviews.llvm.org/D35768

llvm-svn: 309017
This commit is contained in:
Martin Storsjo 2017-07-25 20:00:37 +00:00
parent 1913360a16
commit 82eaf6cb50
4 changed files with 159 additions and 3 deletions

View File

@ -119,7 +119,7 @@ static uint16_t readMOV(uint8_t *Off) {
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 @@ static void applyBranch20T(uint8_t *Off, int32_t V) {
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 @@ uint8_t Baserel::getDefaultType() {
case AMD64:
return IMAGE_REL_BASED_DIR64;
case I386:
case ARMNT:
return IMAGE_REL_BASED_HIGHLOW;
default:
llvm_unreachable("unknown machine type");

View File

@ -369,6 +369,9 @@ public:
uint8_t Type;
};
void applyMOV32T(uint8_t *Off, uint32_t V);
void applyBranch24T(uint8_t *Off, int32_t V);
} // namespace coff
} // namespace lld

View File

@ -215,6 +215,22 @@ static const uint8_t ThunkX86[] = {
0xFF, 0xE0, // jmp eax
};
static const uint8_t ThunkARM[] = {
0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_<FUNCNAME>
0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_<FUNCNAME>
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 @@ public:
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<Baserel> *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 @@ public:
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 @@ Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
return make<ThunkChunkX64>(S, Dir, Helper);
case I386:
return make<ThunkChunkX86>(S, Dir, Helper);
case ARMNT:
return make<ThunkChunkARM>(S, Dir, Helper);
default:
llvm_unreachable("unsupported machine type");
}

View File

@ -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
...