Skip to content

Commit 501c77d

Browse files
authored
[LLD][ELF][ARM] Fix resolution of R_ARM_THM_JUMP8 and R_ARM_THM_JUMP11 for big endian (llvm#126933)
These relocations apply to 16-bit Thumb instructions, so reading 16 bits rather than 32 bits ensures the correct bits are masked and written back. This fixes the incorrect masking and aligns the relocation logic with the instruction encoding. Before this patch, 32 bits were read from the ELF object. This did not align with the instruction size of 16 bits, but the masking incidentally made it all work nonetheless. However, this was the case only in little endian. In big endian mode, the read 32-bit word had to have its bytes reversed. With this byte reordering, the masking would be applied to the wrong bits, hence causing the incorrect encoding to be produced as a result of the relocation resolution. The added test checks the result for both little and big endian modes.
1 parent c1a2292 commit 501c77d

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

lld/ELF/Arch/ARM.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -663,12 +663,12 @@ void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
663663
case R_ARM_THM_JUMP8:
664664
// We do a 9 bit check because val is right-shifted by 1 bit.
665665
checkInt(ctx, loc, val, 9, rel);
666-
write16(ctx, loc, (read32(ctx, loc) & 0xff00) | ((val >> 1) & 0x00ff));
666+
write16(ctx, loc, (read16(ctx, loc) & 0xff00) | ((val >> 1) & 0x00ff));
667667
break;
668668
case R_ARM_THM_JUMP11:
669669
// We do a 12 bit check because val is right-shifted by 1 bit.
670670
checkInt(ctx, loc, val, 12, rel);
671-
write16(ctx, loc, (read32(ctx, loc) & 0xf800) | ((val >> 1) & 0x07ff));
671+
write16(ctx, loc, (read16(ctx, loc) & 0xf800) | ((val >> 1) & 0x07ff));
672672
break;
673673
case R_ARM_THM_JUMP19:
674674
// Encoding T3: Val = S:J2:J1:imm6:imm11:0

lld/test/ELF/arm-thumb-jump8-11.s

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# REQUIRES: arm
2+
3+
# RUN: llvm-mc -triple thumbv6m-arm-eabi --filetype=obj %s -o %t.o
4+
# RUN: ld.lld %t.o -o %t
5+
# RUN: llvm-objdump -d %t --no-show-raw-insn | FileCheck %s --check-prefixes=CHECK,CHECK-LE
6+
7+
# RUN: llvm-mc -triple thumbebv6m-arm-eabi --filetype=obj %s -o %t.o
8+
# RUN: ld.lld %t.o -o %t
9+
# RUN: llvm-objdump -d %t --no-show-raw-insn | FileCheck %s --check-prefixes=CHECK,CHECK-BE
10+
11+
# CHECK-LE: file format elf32-littlearm
12+
# CHECK-BE: file format elf32-bigarm
13+
14+
# CHECK: Disassembly of section .text:
15+
16+
# CHECK-LABEL: [[#%x,TARGET:]] <target>:
17+
# CHECK-NEXT: [[#TARGET]]: bx lr
18+
19+
# CHECK-LABEL: <_start>:
20+
# CHECK-NEXT: b 0x[[#TARGET]] <target>
21+
# CHECK-NEXT: beq 0x[[#TARGET]] <target>
22+
23+
.thumb
24+
.section .text.1, "ax", %progbits
25+
target:
26+
bx lr
27+
28+
.section .text.2, "ax", %progbits
29+
.globl _start
30+
_start:
31+
b.n target // R_ARM_THM_JUMP11
32+
beq.n target // R_ARM_THM_JUMP8

0 commit comments

Comments
 (0)