Skip to content

Commit 9d2097f

Browse files
committed
lld/AArch64: handle more relocation addends
The function getImplicitAddend() is incomplete, as it is possible to cook up object files with other relocation addends. Although using llvm-mc or the clang integrated assembler does not produce such object files, a proprietary assembler known as armasm can: https://developer.arm.com/documentation/101754/0622/armasm-Legacy-Assembler-Reference armasm is in a frozen state, but it is still actively used in a lot of legacy codebases as the directives, macros and operators are very different from the clang integrated assembler. This makes porting a lot of legacy code from armasm syntax impractical for a lot of projects. Some internal testing of projects using open-source clang and lld fell over at link time when legacy armasm objects were included in the link. The goal of this patch is to enable people with legacy armasm objects to be able to use lld as the linker. Sadly armasm uses SHT_REL format relocations for AArch64 rather than SHT_RELA, which causes lld to reject the objects. As a frozen project we know the small number of relocations that the assembler officially supports and won't include (outside the equivalent of the .reloc directive which I think we can rule out of scope as that is not commonly used). The benefit to lld is that it will ease migration from a proprietary to an open-source toolchain. The drawback is the implementation of a small number of SHT_REL relocations. Although this patch doesn't aim to comprehensively cover all possible relocation addends, it does extend lld to work with the relocation addends that armasm produces, using the canonical aaelf64 document as a reference: https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst
1 parent 2606c87 commit 9d2097f

File tree

2 files changed

+41
-9
lines changed

2 files changed

+41
-9
lines changed

lld/ELF/Arch/AArch64.cpp

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ struct AArch64Relaxer {
6969
};
7070
} // namespace
7171

72+
// Return the bits [Start, End] from Val shifted Start bits.
73+
// For instance, getBits(0xF0, 4, 8) returns 0xF.
74+
static uint64_t getBits(uint64_t val, int start, int end) {
75+
uint64_t mask = ((uint64_t)1 << (end + 1 - start)) - 1;
76+
return (val >> start) & mask;
77+
}
78+
7279
AArch64::AArch64() {
7380
copyRel = R_AARCH64_COPY;
7481
relativeRel = R_AARCH64_RELATIVE;
@@ -219,6 +226,10 @@ int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
219226
case R_AARCH64_GLOB_DAT:
220227
case R_AARCH64_JUMP_SLOT:
221228
return 0;
229+
case R_AARCH64_ABS16:
230+
case R_AARCH64_PREL16:
231+
return SignExtend64<16>(read16(buf));
232+
case R_AARCH64_ABS32:
222233
case R_AARCH64_PREL32:
223234
return SignExtend64<32>(read32(buf));
224235
case R_AARCH64_ABS64:
@@ -227,6 +238,30 @@ int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
227238
case R_AARCH64_IRELATIVE:
228239
case R_AARCH64_TLS_TPREL64:
229240
return read64(buf);
241+
case R_AARCH64_MOVW_UABS_G0:
242+
case R_AARCH64_MOVW_UABS_G0_NC:
243+
return getBits(SignExtend64<16>(read16(buf)), 0, 15);
244+
case R_AARCH64_MOVW_UABS_G1:
245+
case R_AARCH64_MOVW_UABS_G1_NC:
246+
return getBits(SignExtend64<32>(read32(buf)), 16, 31);
247+
case R_AARCH64_MOVW_UABS_G2:
248+
case R_AARCH64_MOVW_UABS_G2_NC:
249+
return getBits(read64(buf), 32, 47);
250+
case R_AARCH64_MOVW_UABS_G3:
251+
return getBits(read64(buf), 48, 63);
252+
case R_AARCH64_TSTBR14:
253+
return getBits(SignExtend64<32>(read32(buf)), 2, 15);
254+
case R_AARCH64_CONDBR19:
255+
case R_AARCH64_LD_PREL_LO19:
256+
return getBits(SignExtend64<32>(read32(buf)), 2, 20);
257+
case R_AARCH64_ADD_ABS_LO12_NC:
258+
return getBits(SignExtend64<16>(read16(buf)), 0, 11);
259+
case R_AARCH64_ADR_PREL_PG_HI21:
260+
case R_AARCH64_ADR_PREL_PG_HI21_NC:
261+
return getBits(SignExtend64<32>(read32(buf)), 12, 32);
262+
case R_AARCH64_JUMP26:
263+
case R_AARCH64_CALL26:
264+
return getBits(SignExtend64<32>(read32(buf)), 2, 27);
230265
default:
231266
internalLinkerError(getErrorLocation(buf),
232267
"cannot read addend for relocation " + toString(type));
@@ -330,13 +365,6 @@ static void write32AArch64Addr(uint8_t *l, uint64_t imm) {
330365
write32le(l, (read32le(l) & ~mask) | immLo | immHi);
331366
}
332367

333-
// Return the bits [Start, End] from Val shifted Start bits.
334-
// For instance, getBits(0xF0, 4, 8) returns 0xF.
335-
static uint64_t getBits(uint64_t val, int start, int end) {
336-
uint64_t mask = ((uint64_t)1 << (end + 1 - start)) - 1;
337-
return (val >> start) & mask;
338-
}
339-
340368
static void or32le(uint8_t *p, int32_t v) { write32le(p, read32le(p) | v); }
341369

342370
// Update the immediate field in a AARCH64 ldr, str, and add instruction.

lld/test/ELF/aarch64-reloc-implicit-addend.test

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
## Test certain REL relocation types generated by legacy armasm.
22
# RUN: yaml2obj %s -o %t.o
3-
# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
3+
# RUN: ld.lld %t.o -o %t.out
4+
# RUN: llvm-objdump -t %t.out | FileCheck %s
45

5-
# CHECK-COUNT-17: internal linker error: cannot read addend
6+
# CHECK: SYMBOL TABLE:
7+
# CHECK-NEXT: 0000000000200130 l .branch 0000000000000000 .branch
8+
# CHECK-NEXT: 0000000000200118 l .prel 0000000000000000 .prel
9+
# CHECK-NEXT: 000000000000002a g *ABS* 0000000000000000 abs
610

711
---
812
!ELF

0 commit comments

Comments
 (0)