Index: COFF/Chunks.h =================================================================== --- COFF/Chunks.h +++ COFF/Chunks.h @@ -151,6 +151,8 @@ uint64_t P) const; void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const; + void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; // Called if the garbage collector decides to not include this chunk // in a final output. It's supposed to print out a log message to stdout. @@ -264,6 +266,12 @@ 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip] }; +static const uint8_t ImportThunkARM64[] = { + 0x10, 0x00, 0x00, 0x90, // adrp x16, #0 + 0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16] + 0x00, 0x02, 0x1f, 0xd6, // br x16 +}; + // Windows-specific. // A chunk for DLL import jump table entry. In a final output, it's // contents will be a JMP instruction to some __imp_ symbol. @@ -299,6 +307,17 @@ Defined *ImpSymbol; }; +class ImportThunkChunkARM64 : public Chunk { +public: + explicit ImportThunkChunkARM64(Defined *S) : ImpSymbol(S) {} + size_t getSize() const override { return sizeof(ImportThunkARM64); } + void getBaserels(std::vector *Res) override; + void writeTo(uint8_t *Buf) const override; + +private: + Defined *ImpSymbol; +}; + // Windows-specific. // See comments for DefinedLocalImport class. class LocalImportChunk : public Chunk { Index: COFF/Chunks.cpp =================================================================== --- COFF/Chunks.cpp +++ COFF/Chunks.cpp @@ -52,6 +52,7 @@ static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } +static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); } static void applySecRel(const SectionChunk *Sec, uint8_t *Off, OutputSection *OS, uint64_t S) { @@ -166,6 +167,41 @@ } } +static void applyArm64Addr(uint8_t *Off, uint64_t Imm) { + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; + uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); + write32le(Off, (read32le(Off) & ~Mask) | ImmLo | ImmHi); +} + +// Update the immediate field in a AARCH64 ldr, str, and add instruction. +static void applyArm64Imm(uint8_t *Off, uint64_t Imm) { + uint32_t Orig = read32le(Off); + Imm += (Orig >> 10) & 0xFFF; + Orig &= ~(0xFFF << 10); + write32le(Off, Orig | ((Imm & 0xFFF) << 10)); +} + +static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) { + int Size = read32le(Off) >> 30; + Imm >>= Size; + applyArm64Imm(Off, Imm); +} + +void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { + switch (Type) { + case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, (S >> 12) - (P >> 12)); break; + case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff); break; + case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break; + case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break; + case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break; + default: + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + } +} + void SectionChunk::writeTo(uint8_t *Buf) const { if (!hasData()) return; @@ -210,6 +246,9 @@ case ARMNT: applyRelARM(Off, Rel.Type, OS, S, P); break; + case ARM64: + applyRelARM64(Off, Rel.Type, OS, S, P); + break; default: llvm_unreachable("unknown machine type"); } @@ -236,6 +275,10 @@ if (Rel.Type == IMAGE_REL_ARM_MOV32T) return IMAGE_REL_BASED_ARM_MOV32T; return IMAGE_REL_BASED_ABSOLUTE; + case ARM64: + if (Rel.Type == IMAGE_REL_ARM64_ADDR64) + return IMAGE_REL_BASED_DIR64; + return IMAGE_REL_BASED_ABSOLUTE; default: llvm_unreachable("unknown machine type"); } @@ -345,6 +388,17 @@ applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); } +void ImportThunkChunkARM64::getBaserels(std::vector *Res) { +} + +void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const { + int64_t PageOff = (ImpSymbol->getRVA() >> 12) - (RVA >> 12); + int64_t Off = ImpSymbol->getRVA() & 0xfff; + memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64)); + applyArm64Addr(Buf + OutputSectionOff, PageOff); + applyArm64Ldr(Buf + OutputSectionOff + 4, Off); +} + void LocalImportChunk::getBaserels(std::vector *Res) { Res->emplace_back(getRVA()); } Index: COFF/Symbols.cpp =================================================================== --- COFF/Symbols.cpp +++ COFF/Symbols.cpp @@ -68,6 +68,8 @@ return make(S); if (Machine == I386) return make(S); + if (Machine == ARM64) + return make(S); assert(Machine == ARMNT); return make(S); } Index: test/COFF/arm64-relocs-imports.test =================================================================== --- /dev/null +++ test/COFF/arm64-relocs-imports.test @@ -0,0 +1,136 @@ +# REQUIRES: aarch64 + +# RUN: yaml2obj < %s > %t.obj +# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE +# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj %p/Inputs/library-arm64.lib +# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER + +# BEFORE: Disassembly of section .text: +# BEFORE: 0: fe 0f 1f f8 str x30, [sp, #-16]! +# BEFORE: 4: 00 00 00 90 adrp x0, #0 +# BEFORE: 8: 00 08 00 91 add x0, x0, #2 +# BEFORE: c: 00 00 00 94 bl #0 +# BEFORE: 10: 00 01 40 39 ldrb w0, [x8] +# BEFORE: 14: 00 01 40 79 ldrh w0, [x8] +# BEFORE: 18: 00 01 40 b9 ldr w0, [x8] +# BEFORE: 1c: 00 01 40 f9 ldr x0, [x8] +# BEFORE: 20: e0 03 1f 2a mov w0, wzr +# BEFORE: 24: fe 07 41 f8 ldr x30, [sp], #16 +# BEFORE: 28: c0 03 5f d6 ret +# BEFORE: 2c: 08 00 00 00 +# BEFORE: 30: 00 00 00 00 + +# AFTER: Disassembly of section .text: +# AFTER: 140002000: fe 0f 1f f8 str x30, [sp, #-16]! +# AFTER: 140002004: e0 ff ff f0 adrp x0, #-4096 +# AFTER: 140002008: 00 18 00 91 add x0, x0, #6 +# AFTER: 14000200c: 0a 00 00 94 bl #40 +# AFTER: 140002010: 00 21 40 39 ldrb w0, [x8, #8] +# AFTER: 140002014: 00 11 40 79 ldrh w0, [x8, #8] +# AFTER: 140002018: 00 09 40 b9 ldr w0, [x8, #8] +# AFTER: 14000201c: 00 05 40 f9 ldr x0, [x8, #8] +# AFTER: 140002020: e0 03 1f 2a mov w0, wzr +# AFTER: 140002024: fe 07 41 f8 ldr x30, [sp], #16 +# AFTER: 140002028: c0 03 5f d6 ret +# AFTER: 14000202c: 10 10 00 40 +# AFTER: 140002030: 01 00 00 00 +# AFTER: 140002034: 10 00 00 b0 adrp x16, #4096 +# AFTER: 140002038: 10 1e 40 f9 ldr x16, [x16, #56] +# AFTER: 14000203c: 00 02 1f d6 br x16 + +--- !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: FE0F1FF80000009000080091000000940001403900014079000140B9000140F9E0031F2AFE0741F8C0035FD60800000000000000 + Relocations: + - VirtualAddress: 4 + SymbolName: .Lstr + Type: 4 + - VirtualAddress: 8 + SymbolName: .Lstr + Type: 6 + - VirtualAddress: 12 + SymbolName: function + Type: 3 + - VirtualAddress: 16 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 20 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 24 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 28 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 44 + SymbolName: .Lglobal + Type: 14 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 00000000202068656C6C6F20776F726C6400 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 28 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 1438860354 + Number: 1 + - Name: .rdata + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 872944732 + Number: 4 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: .Lstr + Value: 4 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .Lglobal + Value: 8 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: function + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +...