mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-26 11:25:27 +00:00
Add initial support for Thumb for ARMv7a
Add support for the R_ARM_THM relocations used in the objects present in arm-linux-gnueabihf-gcc. These are: R_ARM_THM_CALL R_ARM_THM_JUMP11 R_ARM_THM_JUMP19 R_ARM_THM_JUMP24 R_ARM_THM_MOVT_ABS R_ARM_THM_MOVW_ABS_NC Interworking between ARM and Thumb is partially supported with BLX. The R_ARM_CALL relocation for ARM instructions and R_ARM_THM_CALL relocation for Thumb instructions will write out a BL or BLX depending on the state of the Target. Assumptions: - Availability of BLX and extended range of Thumb 4-byte Branch instructions. - In relocateOne if (Val & 0x1) == 1 target is Thumb, 0 is ARM. This will hold for objects that comply with the ABI for the ARM architecture. This is sufficient for hello world to work with a recent arm-linux-gnueabihf distribution. Limitations: No interworking for R_ARM_JUMP24, R_ARM_THM_JUMP24, R_ARM_THM_JUMP19 and the deprecated R_ARM_PLT32 and R_ARM_PC24 instructions as these cannot be written out as a BLX and need a state change thunk. No range extension thunks. The R_ARM_JUMP24 and R_ARM_THM_CALL have a range of 16Mb llvm-svn: 272881
This commit is contained in:
parent
1d14864bb3
commit
fa4d90d5aa
@ -1460,10 +1460,15 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
|
||||
switch (Type) {
|
||||
default:
|
||||
return R_ABS;
|
||||
case R_ARM_THM_JUMP11:
|
||||
return R_PC;
|
||||
case R_ARM_CALL:
|
||||
case R_ARM_JUMP24:
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_PLT32:
|
||||
case R_ARM_THM_JUMP19:
|
||||
case R_ARM_THM_JUMP24:
|
||||
case R_ARM_THM_CALL:
|
||||
return R_PLT_PC;
|
||||
case R_ARM_GOTOFF32:
|
||||
// (S + A) - GOT_ORG
|
||||
@ -1546,12 +1551,70 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
|
||||
write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
|
||||
break;
|
||||
case R_ARM_CALL:
|
||||
// R_ARM_CALL is used for BL and BLX instructions, depending on the
|
||||
// value of bit 0 of Val, we must select a BL or BLX instruction
|
||||
if (Val & 1) {
|
||||
// If bit 0 of Val is 1 the target is Thumb, we must select a BLX.
|
||||
// The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'
|
||||
checkInt<26>(Val, Type);
|
||||
write32le(Loc, 0xfa000000 | // opcode
|
||||
((Val & 2) << 23) | // H
|
||||
((Val >> 2) & 0x00ffffff)); // imm24
|
||||
break;
|
||||
}
|
||||
if ((read32le(Loc) & 0xfe000000) == 0xfa000000)
|
||||
// BLX (always unconditional) instruction to an ARM Target, select an
|
||||
// unconditional BL.
|
||||
write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff));
|
||||
// fall through as BL encoding is shared with B
|
||||
case R_ARM_JUMP24:
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_PLT32:
|
||||
checkInt<26>(Val, Type);
|
||||
write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
|
||||
break;
|
||||
case R_ARM_THM_JUMP11:
|
||||
checkInt<12>(Val, Type);
|
||||
write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff));
|
||||
break;
|
||||
case R_ARM_THM_JUMP19:
|
||||
// Encoding T3: Val = S:J2:J1:imm6:imm11:0
|
||||
checkInt<21>(Val, Type);
|
||||
write16le(Loc,
|
||||
(read16le(Loc) & 0xfbc0) | // opcode cond
|
||||
((Val >> 10) & 0x0400) | // S
|
||||
((Val >> 12) & 0x003f)); // imm6
|
||||
write16le(Loc + 2,
|
||||
0x8000 | // opcode
|
||||
((Val >> 8) & 0x0800) | // J2
|
||||
((Val >> 5) & 0x2000) | // J1
|
||||
((Val >> 1) & 0x07ff)); // imm11
|
||||
break;
|
||||
case R_ARM_THM_CALL:
|
||||
// R_ARM_THM_CALL is used for BL and BLX instructions, depending on the
|
||||
// value of bit 0 of Val, we must select a BL or BLX instruction
|
||||
if ((Val & 1) == 0) {
|
||||
// Ensure BLX destination is 4-byte aligned. As BLX instruction may
|
||||
// only be two byte aligned. This must be done before overflow check
|
||||
Val = alignTo(Val, 4);
|
||||
}
|
||||
// Bit 12 is 0 for BLX, 1 for BL
|
||||
write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12);
|
||||
// Fall through as rest of encoding is the same as B.W
|
||||
case R_ARM_THM_JUMP24:
|
||||
// Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
|
||||
// FIXME: Use of I1 and I2 require v6T2ops
|
||||
checkInt<25>(Val, Type);
|
||||
write16le(Loc,
|
||||
0xf000 | // opcode
|
||||
((Val >> 14) & 0x0400) | // S
|
||||
((Val >> 12) & 0x03ff)); // imm10
|
||||
write16le(Loc + 2,
|
||||
(read16le(Loc + 2) & 0xd000) | // opcode
|
||||
(((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1
|
||||
(((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2
|
||||
((Val >> 1) & 0x07ff)); // imm11
|
||||
break;
|
||||
case R_ARM_MOVW_ABS_NC:
|
||||
write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) |
|
||||
(Val & 0x0fff));
|
||||
@ -1561,6 +1624,29 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
|
||||
write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
|
||||
(((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
|
||||
break;
|
||||
case R_ARM_THM_MOVT_ABS:
|
||||
// Encoding T1: A = imm4:i:imm3:imm8
|
||||
checkUInt<32>(Val, Type);
|
||||
write16le(Loc,
|
||||
0xf2c0 | // opcode
|
||||
((Val >> 17) & 0x0400) | // i
|
||||
((Val >> 28) & 0x000f)); // imm4
|
||||
write16le(Loc + 2,
|
||||
(read16le(Loc + 2) & 0x8f00) | // opcode
|
||||
((Val >> 12) & 0x7000) | // imm3
|
||||
((Val >> 16) & 0x00ff)); // imm8
|
||||
break;
|
||||
case R_ARM_THM_MOVW_ABS_NC:
|
||||
// Encoding T3: A = imm4:i:imm3:imm8
|
||||
write16le(Loc,
|
||||
0xf240 | // opcode
|
||||
((Val >> 1) & 0x0400) | // i
|
||||
((Val >> 12) & 0x000f)); // imm4
|
||||
write16le(Loc + 2,
|
||||
(read16le(Loc + 2) & 0x8f00) | // opcode
|
||||
((Val << 4) & 0x7000) | // imm3
|
||||
(Val & 0x00ff)); // imm8
|
||||
break;
|
||||
default:
|
||||
fatal("unrecognized reloc " + Twine(Type));
|
||||
}
|
||||
@ -1585,13 +1671,48 @@ uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_PLT32:
|
||||
return SignExtend64<26>((read32le(Buf) & 0x00ffffff) << 2);
|
||||
case R_ARM_THM_JUMP11:
|
||||
return SignExtend64<12>((read16le(Buf) & 0x07ff) << 1);
|
||||
case R_ARM_THM_JUMP19: {
|
||||
// Encoding T3: A = S:J2:J1:imm10:imm6:0
|
||||
uint16_t Hi = read16le(Buf);
|
||||
uint16_t Lo = read16le(Buf + 2);
|
||||
return SignExtend64<20>(((Hi & 0x0400) << 10) | // S
|
||||
((Lo & 0x0800) << 8) | // J2
|
||||
((Lo & 0x2000) << 5) | // J1
|
||||
((Hi & 0x003f) << 12) | // imm6
|
||||
((Lo & 0x07ff) << 1)); // imm11:0
|
||||
}
|
||||
case R_ARM_THM_JUMP24:
|
||||
case R_ARM_THM_CALL: {
|
||||
// Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0
|
||||
// I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S)
|
||||
// FIXME: I1 and I2 require v6T2ops
|
||||
uint16_t Hi = read16le(Buf);
|
||||
uint16_t Lo = read16le(Buf + 2);
|
||||
return SignExtend64<24>(((Hi & 0x0400) << 14) | // S
|
||||
(~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1
|
||||
(~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2
|
||||
((Hi & 0x003ff) << 12) | // imm0
|
||||
((Lo & 0x007ff) << 1)); // imm11:0
|
||||
}
|
||||
// ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and
|
||||
// MOVT is in the range -32768 <= A < 32768
|
||||
case R_ARM_MOVW_ABS_NC:
|
||||
case R_ARM_MOVT_ABS: {
|
||||
// ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and
|
||||
// MOVT is in the range -32768 <= A < 32768
|
||||
uint64_t Val = read32le(Buf) & 0x000f0fff;
|
||||
return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff));
|
||||
}
|
||||
case R_ARM_THM_MOVW_ABS_NC:
|
||||
case R_ARM_THM_MOVT_ABS: {
|
||||
// Encoding T3: A = imm4:i:imm3:imm8
|
||||
uint16_t Hi = read16le(Buf);
|
||||
uint16_t Lo = read16le(Buf + 2);
|
||||
return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4
|
||||
((Hi & 0x0400) << 1) | // i
|
||||
((Lo & 0x7000) >> 4) | // imm3
|
||||
(Lo & 0x00ff)); // imm8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
36
lld/test/ELF/Inputs/arm-thumb-blx-targets.s
Normal file
36
lld/test/ELF/Inputs/arm-thumb-blx-targets.s
Normal file
@ -0,0 +1,36 @@
|
||||
.syntax unified
|
||||
.arm
|
||||
.section .R_ARM_CALL24_callee_low, "ax",%progbits
|
||||
.align 2
|
||||
.globl callee_low
|
||||
.type callee_low,%function
|
||||
callee_low:
|
||||
bx lr
|
||||
|
||||
.section .R_ARM_CALL24_callee_thumb_low, "ax",%progbits
|
||||
.balign 0x100
|
||||
.thumb
|
||||
.type callee_thumb_low,%function
|
||||
.globl callee_thumb_low
|
||||
callee_thumb_low:
|
||||
bx lr
|
||||
|
||||
.section .R_ARM_CALL24_callee_high, "ax",%progbits
|
||||
.balign 0x100
|
||||
.arm
|
||||
.globl callee_high
|
||||
.type callee_high,%function
|
||||
callee_high:
|
||||
bx lr
|
||||
|
||||
.section .R_ARM_CALL24_callee_thumb_high, "ax",%progbits
|
||||
.balign 0x100
|
||||
.thumb
|
||||
.type callee_thumb_high,%function
|
||||
.globl callee_thumb_high
|
||||
callee_thumb_high:
|
||||
bx lr
|
||||
|
||||
.globl blx_far
|
||||
.type blx_far, %function
|
||||
blx_far = 0x1010018
|
BIN
lld/test/ELF/Inputs/arm-thumb-narrow-branch.o
Normal file
BIN
lld/test/ELF/Inputs/arm-thumb-narrow-branch.o
Normal file
Binary file not shown.
18
lld/test/ELF/Inputs/arm-thumb-narrow-branch.s
Normal file
18
lld/test/ELF/Inputs/arm-thumb-narrow-branch.s
Normal file
@ -0,0 +1,18 @@
|
||||
// This input must be assembled by the GNU assembler, as llvm-mc does not emit
|
||||
// the R_ARM_JUMP11 relocation for a Thumb narrow branch. This is permissible
|
||||
// by the ABI for the ARM architecture as the range of the Thumb narrow branch
|
||||
// is short enough (+- 2048 bytes) that widespread use would be impractical.
|
||||
//
|
||||
// The test case will use a pre compiled object arm-thumb-narrow-branch.o
|
||||
.syntax unified
|
||||
.section .caller, "ax",%progbits
|
||||
.thumb
|
||||
.align 2
|
||||
.type callers,%function
|
||||
.globl callers
|
||||
callers:
|
||||
b.n callee_low_far
|
||||
b.n callee_low
|
||||
b.n callee_high
|
||||
b.n callee_high_far
|
||||
bx lr
|
24
lld/test/ELF/Inputs/far-arm-thumb-abs.s
Normal file
24
lld/test/ELF/Inputs/far-arm-thumb-abs.s
Normal file
@ -0,0 +1,24 @@
|
||||
.global far_cond
|
||||
.type far_cond,%function
|
||||
far_cond = 0x110023
|
||||
.global far_uncond
|
||||
.type far_uncond,%function
|
||||
far_uncond = 0x101001b
|
||||
|
||||
.global too_far1
|
||||
.type too_far1,%function
|
||||
too_far1 = 0x1020005
|
||||
.global too_far2
|
||||
.type too_far1,%function
|
||||
too_far2 = 0x1020009
|
||||
.global too_far3
|
||||
.type too_far3,%function
|
||||
too_far3 = 0x12000d
|
||||
|
||||
.global blx_far
|
||||
.type blx_far, %function
|
||||
blx_far = 0x2010025
|
||||
|
||||
.global blx_far2
|
||||
.type blx_far2, %function
|
||||
blx_far2 = 0x2010029
|
113
lld/test/ELF/arm-blx.s
Normal file
113
lld/test/ELF/arm-blx.s
Normal file
@ -0,0 +1,113 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
|
||||
// RUN: echo "SECTIONS { \
|
||||
// RUN: .callee1 : { *(.callee_low) } \
|
||||
// RUN: .callee2 : { *(.callee_arm_low) } \
|
||||
// RUN: .caller : { *(.text) } \
|
||||
// RUN: .callee3 : { *(.callee_high) } \
|
||||
// RUN: .callee4 : { *(.callee_arm_high) } } " > %t.script
|
||||
// RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1
|
||||
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM %s
|
||||
// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB %s
|
||||
// REQUIRES: arm
|
||||
|
||||
// Test BLX instruction is chosen for ARM BL/BLX instruction and Thumb callee
|
||||
// Using two callees to ensure at least one has 2-byte alignment.
|
||||
.syntax unified
|
||||
.thumb
|
||||
.section .callee_low, "ax",%progbits
|
||||
.align 2
|
||||
.type callee_low,%function
|
||||
callee_low:
|
||||
bx lr
|
||||
.type callee_low2, %function
|
||||
callee_low2:
|
||||
bx lr
|
||||
|
||||
.section .callee_arm_low, "ax",%progbits
|
||||
.arm
|
||||
.balign 0x100
|
||||
.type callee_arm_low,%function
|
||||
.align 2
|
||||
callee_arm_low:
|
||||
bx lr
|
||||
|
||||
.section .text, "ax",%progbits
|
||||
.arm
|
||||
.globl _start
|
||||
.balign 0x10000
|
||||
.type _start,%function
|
||||
_start:
|
||||
bl callee_low
|
||||
blx callee_low
|
||||
bl callee_low2
|
||||
blx callee_low2
|
||||
bl callee_high
|
||||
blx callee_high
|
||||
bl callee_high2
|
||||
blx callee_high2
|
||||
bl blx_far
|
||||
blx blx_far2
|
||||
// blx to ARM instruction should be written as a BL
|
||||
bl callee_arm_low
|
||||
blx callee_arm_low
|
||||
bl callee_arm_high
|
||||
blx callee_arm_high
|
||||
bx lr
|
||||
|
||||
.section .callee_high, "ax",%progbits
|
||||
.balign 0x100
|
||||
.thumb
|
||||
.type callee_high,%function
|
||||
callee_high:
|
||||
bx lr
|
||||
.type callee_high2,%function
|
||||
callee_high2:
|
||||
bx lr
|
||||
|
||||
.section .callee_arm_high, "ax",%progbits
|
||||
.arm
|
||||
.balign 0x100
|
||||
.type callee_arm_high,%function
|
||||
callee_arm_high:
|
||||
bx lr
|
||||
|
||||
// CHECK-THUMB: Disassembly of section .callee1:
|
||||
// CHECK-THUMB-NEXT: callee_low:
|
||||
// CHECK-THUMB-NEXT: b4: 70 47 bx lr
|
||||
// CHECK-THUMB: callee_low2:
|
||||
// CHECK-THUMB-NEXT: b6: 70 47 bx lr
|
||||
|
||||
// CHECK-ARM: Disassembly of section .callee2:
|
||||
// CHECK-ARM-NEXT: callee_arm_low:
|
||||
// CHECK-ARM-NEXT: 100: 1e ff 2f e1 bx lr
|
||||
|
||||
// CHECK-ARM: Disassembly of section .caller:
|
||||
// CHECK-ARM-NEXT: _start:
|
||||
// CHECK-ARM-NEXT: 10000: 2b c0 ff fa blx #-65364 <callee_low>
|
||||
// CHECK-ARM-NEXT: 10004: 2a c0 ff fa blx #-65368 <callee_low>
|
||||
// CHECK-ARM-NEXT: 10008: 29 c0 ff fb blx #-65370 <callee_low2>
|
||||
// CHECK-ARM-NEXT: 1000c: 28 c0 ff fb blx #-65374 <callee_low2>
|
||||
// CHECK-ARM-NEXT: 10010: 3a 00 00 fa blx #232 <callee_high>
|
||||
// CHECK-ARM-NEXT: 10014: 39 00 00 fa blx #228 <callee_high>
|
||||
// CHECK-ARM-NEXT: 10018: 38 00 00 fb blx #226 <callee_high2>
|
||||
// CHECK-ARM-NEXT: 1001c: 37 00 00 fb blx #222 <callee_high2>
|
||||
// 10020 + 1FFFFFC + 8 = 0x2010024 = blx_far
|
||||
// CHECK-ARM-NEXT: 10020: ff ff 7f fa blx #33554428
|
||||
// 10024 + 1FFFFFC + 8 = 0x2010028 = blx_far2
|
||||
// CHECK-ARM-NEXT: 10024: ff ff 7f fa blx #33554428
|
||||
// CHECK-ARM-NEXT: 10028: 34 c0 ff eb bl #-65328 <callee_arm_low>
|
||||
// CHECK-ARM-NEXT: 1002c: 33 c0 ff eb bl #-65332 <callee_arm_low>
|
||||
// CHECK-ARM-NEXT: 10030: 72 00 00 eb bl #456 <callee_arm_high>
|
||||
// CHECK-ARM-NEXT: 10034: 71 00 00 eb bl #452 <callee_arm_high>
|
||||
// CHECK-ARM-NEXT: 10038: 1e ff 2f e1 bx lr
|
||||
|
||||
// CHECK-THUMB: Disassembly of section .callee3:
|
||||
// CHECK-THUMB: callee_high:
|
||||
// CHECK-THUMB-NEXT: 10100: 70 47 bx lr
|
||||
// CHECK-THUMB: callee_high2:
|
||||
// CHECK-THUMB-NEXT: 10102: 70 47 bx lr
|
||||
|
||||
// CHECK-ARM: Disassembly of section .callee4:
|
||||
// CHECK-NEXT-ARM: callee_arm_high:
|
||||
// CHECK-NEXT-ARM: 10200: 1e ff 2f e1 bx lr
|
@ -1,9 +1,13 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-unknown-linux-gnueabi %s -o %t
|
||||
// RUN: ld.lld %t -o %t2
|
||||
// RUN: llvm-objdump -d %t2 -triple=armv7a-unknown-linux-gnueabi | FileCheck %s
|
||||
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-unknown-linux-gnueabi %s -o %t3
|
||||
// RUN: ld.lld %t3 -o %t4
|
||||
// RUN: llvm-objdump -d %t4 -triple=thumbv7a-unknown-linux-gnueabi | FileCheck %s
|
||||
// REQUIRES: arm
|
||||
|
||||
// Test the R_ARM_MOVW_ABS_NC and R_ARM_MOVT_ABS relocations
|
||||
// Test the R_ARM_MOVW_ABS_NC and R_ARM_MOVT_ABS relocations as well as
|
||||
// the R_ARM_THM_MOVW_ABS_NC and R_ARM_THM_MOVT_ABS relocations.
|
||||
.syntax unified
|
||||
.globl _start
|
||||
_start:
|
||||
|
85
lld/test/ELF/arm-thumb-blx.s
Normal file
85
lld/test/ELF/arm-thumb-blx.s
Normal file
@ -0,0 +1,85 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
|
||||
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/arm-thumb-blx-targets.s -o %ttarget
|
||||
// RUN: echo "SECTIONS { \
|
||||
// RUN: .R_ARM_CALL24_callee1 : { *(.R_ARM_CALL24_callee_low) } \
|
||||
// RUN: .R_ARM_CALL24_callee2 : { *(.R_ARM_CALL24_callee_thumb_low) } \
|
||||
// RUN: .caller : { *(.text) } \
|
||||
// RUN: .R_ARM_CALL24_callee3 : { *(.R_ARM_CALL24_callee_high) } \
|
||||
// RUN: .R_ARM_CALL24_callee4 : { *(.R_ARM_CALL24_callee_thumb_high) } } " > %t.script
|
||||
// RUN: ld.lld --script %t.script %t %ttarget -o %t2 2>&1
|
||||
// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB %s
|
||||
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM %s
|
||||
// REQUIRES: arm
|
||||
// Test BLX instruction is chosen for Thumb BL/BLX instruction and ARM callee
|
||||
// 2 byte nops are used to test the pc-rounding behaviour. As a BLX from a
|
||||
// 2 byte aligned destination is defined as Align(PC,4) + immediate:00
|
||||
// FIXME: llvm-mc has problems assembling BLX unless the destination is
|
||||
// external. The targets of the BL and BLX instructions are in arm-thumb-blx-target.s
|
||||
.syntax unified
|
||||
.section .text, "ax",%progbits
|
||||
.thumb
|
||||
.globl _start
|
||||
.balign 0x10000
|
||||
.type _start,%function
|
||||
_start:
|
||||
blx callee_low
|
||||
nop
|
||||
bl callee_low
|
||||
nop
|
||||
blx callee_high
|
||||
nop
|
||||
bl callee_high
|
||||
nop
|
||||
blx blx_far
|
||||
nop
|
||||
bl blx_far
|
||||
nop
|
||||
// Expect BLX to thumb target to be written out as a BL
|
||||
blx callee_thumb_low
|
||||
nop
|
||||
blx callee_thumb_high
|
||||
bx lr
|
||||
|
||||
// CHECK-ARM: Disassembly of section .R_ARM_CALL24_callee1:
|
||||
// CHECK-NEXT-ARM: callee_low:
|
||||
// CHECK-NEXT-ARM: b4: 1e ff 2f e1 bx lr
|
||||
|
||||
// CHECK-THUMB: Disassembly of section .R_ARM_CALL24_callee2:
|
||||
// CHECK-NEXT-THUMB: callee_thumb_low:
|
||||
// CHECK-NEXT-THUMB: 100: 70 47 bx lr
|
||||
|
||||
// CHECK-THUMB: Disassembly of section .caller:
|
||||
// CHECK-THUMB: _start:
|
||||
// Align(0x10000,4) - 0xff50 (65360) + 4 = 0xb4 = callee_low
|
||||
// CHECK-NEXT-THUMB: 10000: f0 f7 58 e8 blx #-65360
|
||||
// CHECK-NEXT-THUMB: 10004: 00 bf nop
|
||||
// Align(0x10006,4) - 0xff54 (65364) + 4 = 0xb4 = callee_low
|
||||
// CHECK-NEXT-THUMB: 10006: f0 f7 56 e8 blx #-65364
|
||||
// CHECK-NEXT-THUMB: 1000a: 00 bf nop
|
||||
// Align(0x1000c,4) + 0xf0 (240) + 4 = 0x10100 = callee_high
|
||||
// CHECK-NEXT-THUMB: 1000c: 00 f0 78 e8 blx #240
|
||||
// CHECK-NEXT-THUMB: 10010: 00 bf nop
|
||||
// Align(0x10012,4) + 0xec (236) + 4 = 0x10100 = callee_high
|
||||
// CHECK-NEXT-THUMB: 10012: 00 f0 76 e8 blx #236
|
||||
// CHECK-NEXT-THUMB: 10016: 00 bf nop
|
||||
// Align(0x10018,4) + 0xfffffc (16777212) = 0x1010018 = blx_far
|
||||
// CHECK-NEXT-THUMB: 10018: ff f3 fe c7 blx #16777212
|
||||
// CHECK-NEXT-THUMB: 1001c: 00 bf nop
|
||||
// Align(0x1001e,4) + 0xfffff8 (16777208) = 0x1010018 = blx_far
|
||||
// CHECK-NEXT-THUMB: 1001e: ff f3 fc c7 blx #16777208
|
||||
// CHECK-NEXT-THUMB: 10022: 00 bf nop
|
||||
// 10024 - 0xff28 (65320) + 4 = 0x100 = callee_thumb_low
|
||||
// CHECK-NEXT-THUMB: 10024: f0 f7 6c f8 bl #-65320
|
||||
// CHECK-NEXT-THUMB: 10028: 00 bf nop
|
||||
// 1002a + 0x1d2 (466) + 4 = 0x10200 = callee_thumb_high
|
||||
// CHECK-NEXT-THUMB: 1002a: 00 f0 e9 f8 bl #466
|
||||
// CHECK-NEXT-THUMB: 1002e: 70 47 bx lr
|
||||
|
||||
|
||||
// CHECK-ARM: Disassembly of section .R_ARM_CALL24_callee3:
|
||||
// CHECK-NEXT-ARM: callee_high:
|
||||
// CHECK-NEXT-ARM: 10100: 1e ff 2f e1 bx lr
|
||||
|
||||
// CHECK: Disassembly of section .R_ARM_CALL24_callee4:
|
||||
// CHECK-NEXT-THUMB:callee_thumb_high:
|
||||
// CHECK-NEXT-THUMB: 10200: 70 47 bx lr
|
19
lld/test/ELF/arm-thumb-branch-error.s
Normal file
19
lld/test/ELF/arm-thumb-branch-error.s
Normal file
@ -0,0 +1,19 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
|
||||
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
|
||||
// RUN: not ld.lld %t %tfar -o %t2 2>&1 | FileCheck %s
|
||||
// REQUIRES: arm
|
||||
.syntax unified
|
||||
.section .text, "ax",%progbits
|
||||
.globl _start
|
||||
.balign 0x10000
|
||||
.type _start,%function
|
||||
_start:
|
||||
// address of too_far symbols are just out of range of ARM branch with
|
||||
// 26-bit immediate field and an addend of -8
|
||||
bl too_far1
|
||||
b too_far2
|
||||
beq.w too_far3
|
||||
|
||||
// CHECK: R_ARM_THM_CALL out of range
|
||||
// CHECK-NEXT: R_ARM_THM_JUMP24 out of range
|
||||
// CHECK-NEXT: R_ARM_THM_JUMP19 out of range
|
59
lld/test/ELF/arm-thumb-branch.s
Normal file
59
lld/test/ELF/arm-thumb-branch.s
Normal file
@ -0,0 +1,59 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
|
||||
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
|
||||
// RUN: echo "SECTIONS { \
|
||||
// RUN: .callee1 : { *(.callee_low) } \
|
||||
// RUN: .caller : { *(.text) } \
|
||||
// RUN: .callee2 : { *(.callee_high) } } " > %t.script
|
||||
// RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1
|
||||
// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck %s
|
||||
// REQUIRES: arm
|
||||
|
||||
.syntax unified
|
||||
.thumb
|
||||
.section .callee_low, "ax",%progbits
|
||||
.align 2
|
||||
.type callee_low,%function
|
||||
callee_low:
|
||||
bx lr
|
||||
|
||||
.section .text, "ax",%progbits
|
||||
.globl _start
|
||||
.balign 0x10000
|
||||
.type _start,%function
|
||||
_start:
|
||||
bl callee_low
|
||||
b callee_low
|
||||
beq callee_low
|
||||
bl callee_high
|
||||
b callee_high
|
||||
bne callee_high
|
||||
bl far_uncond
|
||||
b far_uncond
|
||||
bgt far_cond
|
||||
bx lr
|
||||
|
||||
.section .callee_high, "ax",%progbits
|
||||
.align 2
|
||||
.type callee_high,%function
|
||||
callee_high:
|
||||
bx lr
|
||||
|
||||
// CHECK: Disassembly of section .callee1:
|
||||
// CHECK-NEXT: callee_low:
|
||||
// CHECK-NEXT: b4: 70 47 bx lr
|
||||
// CHECK-NEXT: Disassembly of section .caller:
|
||||
// CHECK-NEXT: _start:
|
||||
// CHECK-NEXT: 10000: f0 f7 58 f8 bl #-65360
|
||||
// CHECK-NEXT: 10004: f0 f7 56 b8 b.w #-65364
|
||||
// CHECK-NEXT: 10008: 30 f4 54 a8 beq.w #-65368
|
||||
// CHECK-NEXT: 1000c: 00 f0 0c f8 bl #24
|
||||
// CHECK-NEXT: 10010: 00 f0 0a b8 b.w #20
|
||||
// CHECK-NEXT: 10014: 40 f0 08 80 bne.w #16
|
||||
// CHECK-NEXT: 10018: ff f3 ff d7 bl #16777214
|
||||
// CHECK-NEXT: 1001c: ff f3 fd 97 b.w #16777210
|
||||
// CHECK-NEXT: 10020: 3f f3 ff af bgt.w #1048574
|
||||
// CHECK-NEXT: 10024: 70 47 bx lr
|
||||
// CHECK-NEXT: 10026: 00 00 movs r0, r0
|
||||
// CHECK-NEXT: Disassembly of section .callee2:
|
||||
// CHECK-NEXT: callee_high:
|
||||
// CHECK-NEXT: 10028: 70 47 bx lr
|
72
lld/test/ELF/arm-thumb-narrow-branch-check.s
Normal file
72
lld/test/ELF/arm-thumb-narrow-branch-check.s
Normal file
@ -0,0 +1,72 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
|
||||
// RUN: echo "SECTIONS { \
|
||||
// RUN: .R_ARM_PC11_1 : { *(.R_ARM_PC11_1) } \
|
||||
// RUN: .caller : { *(.caller) } \
|
||||
// RUN: .R_ARM_PC11_2 : { *(.R_ARM_PC11_2) } \
|
||||
// RUN: .text : { *(.text) } } " > %t.script
|
||||
// RUN: ld.lld --script %t.script %t %S/Inputs/arm-thumb-narrow-branch.o -o %t2 2>&1
|
||||
// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck %s
|
||||
// REQUIRES: arm
|
||||
|
||||
// Test the R_ARM_PC11 relocation which is used with the narrow encoding of B.N
|
||||
// the source of these relocations is a binary file arm-thumb-narrow-branch.o
|
||||
// which has been assembled with the GNU assembler as llvm-mc doesn't emit it
|
||||
// as the range of +-2048 bytes is too small to be practically useful for out
|
||||
// of section branches.
|
||||
.syntax unified
|
||||
|
||||
.global callee_low_far
|
||||
.type callee_low_far,%function
|
||||
callee_low_far = 0x809
|
||||
|
||||
.section .R_ARM_PC11_1,"ax",%progbits
|
||||
.thumb
|
||||
.balign 0x1000
|
||||
.type callee_low,%function
|
||||
.globl callee_low
|
||||
callee_low:
|
||||
bx lr
|
||||
|
||||
.text
|
||||
.align 2
|
||||
.thumb
|
||||
.globl _start
|
||||
.type _start, %function
|
||||
_start:
|
||||
bl callers
|
||||
bx lr
|
||||
|
||||
.section .R_ARM_PC11_2,"ax",%progbits
|
||||
.thumb
|
||||
.align 2
|
||||
.type callee_high,%function
|
||||
.globl callee_high
|
||||
callee_high:
|
||||
bx lr
|
||||
|
||||
.global callee_high_far
|
||||
.type callee_high_far,%function
|
||||
callee_high_far = 0x180d
|
||||
|
||||
// CHECK: Disassembly of section .R_ARM_PC11_1:
|
||||
// CHECK-NEXT: callee_low:
|
||||
// CHECK-NEXT: 1000: 70 47 bx lr
|
||||
// CHECK-NEXT: Disassembly of section .caller:
|
||||
// CHECK-NEXT: callers:
|
||||
// 1004 - 0x800 (2048) + 4 = 0x808 = callee_low_far
|
||||
// CHECK-NEXT: 1004: 00 e4 b #-2048
|
||||
// 1006 - 0xa (10) + 4 = 0x1000 = callee_low
|
||||
// CHECK-NEXT: 1006: fb e7 b #-10
|
||||
// 1008 + 4 + 4 = 0x1010 = callee_high
|
||||
// CHECK-NEXT: 1008: 02 e0 b #4
|
||||
// 100a + 0x7fe (2046) + 4 = 0x180c = callee_high_far
|
||||
// CHECK-NEXT: 100a: ff e3 b #2046
|
||||
// CHECK-NEXT: 100c: 70 47 bx lr
|
||||
// CHECK-NEXT: 100e: 00 bf nop
|
||||
// CHECK-NEXT: Disassembly of section .R_ARM_PC11_2:
|
||||
// CHECK-NEXT: callee_high:
|
||||
// CHECK-NEXT: 1010: 70 47 bx lr
|
||||
// CHECK-NEXT: Disassembly of section .text:
|
||||
// CHECK-NEXT: _start:
|
||||
// CHECK-NEXT: 1014: ff f7 f6 ff bl #-20
|
||||
// CHECK-NEXT: 1018: 70 47 bx lr
|
101
lld/test/ELF/arm-thumb-plt-reloc.s
Normal file
101
lld/test/ELF/arm-thumb-plt-reloc.s
Normal file
@ -0,0 +1,101 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %p/Inputs/arm-plt-reloc.s -o %t1
|
||||
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t2
|
||||
// RUN: ld.lld %t1 %t2 -o %t
|
||||
// RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t | FileCheck %s
|
||||
// RUN: ld.lld -shared %t1 %t2 -o %t3
|
||||
// RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOTHUMB %s
|
||||
// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOARM %s
|
||||
// RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s
|
||||
// REQUIRES: arm
|
||||
//
|
||||
// Test PLT entry generation
|
||||
.syntax unified
|
||||
.text
|
||||
.align 2
|
||||
.globl _start
|
||||
.type _start,%function
|
||||
_start:
|
||||
// FIXME, interworking is only supported for BL via BLX at the moment, when
|
||||
// interworking thunks are available for b.w and b<cond>.w this can be altered
|
||||
// to test the different forms of interworking.
|
||||
bl func1
|
||||
bl func2
|
||||
bl func3
|
||||
|
||||
// Executable, expect no PLT
|
||||
// CHECK: Disassembly of section .text:
|
||||
// CHECK-NEXT: func1:
|
||||
// CHECK-NEXT: 11000: 70 47 bx lr
|
||||
// CHECK: func2:
|
||||
// CHECK-NEXT: 11002: 70 47 bx lr
|
||||
// CHECK: func3:
|
||||
// CHECK-NEXT: 11004: 70 47 bx lr
|
||||
// CHECK-NEXT: 11006: 00 00 movs r0, r0
|
||||
// CHECK: _start:
|
||||
// 11008 + 4 -12 = 0x11000 = func1
|
||||
// CHECK-NEXT: 11008: ff f7 fa ff bl #-12
|
||||
// 1100c + 4 -14 = 0x11002 = func2
|
||||
// CHECK-NEXT: 1100c: ff f7 f9 ff bl #-14
|
||||
// 11010 + 4 -16 = 0x11004 = func3
|
||||
// CHECK-NEXT: 11010: ff f7 f8 ff bl #-16
|
||||
|
||||
// Expect PLT entries as symbols can be preempted
|
||||
// .text is Thumb and .plt is ARM, llvm-objdump can currently only disassemble
|
||||
// as ARM or Thumb. Work around by disassembling twice.
|
||||
// DSOTHUMB: Disassembly of section .text:
|
||||
// DSOTHUMB: func1:
|
||||
// DSOTHUMB-NEXT: 1000: 70 47 bx lr
|
||||
// DSOTHUMB: func2:
|
||||
// DSOTHUMB-NEXT: 1002: 70 47 bx lr
|
||||
// DSOTHUMB: func3:
|
||||
// DSOTHUMB-NEXT: 1004: 70 47 bx lr
|
||||
// DSOTHUMB-NEXT: 1006: 00 00 movs r0, r0
|
||||
// DSOTHUMB: _start:
|
||||
// 0x1008 + 0x28 + 4 = 0x1034 = PLT func1
|
||||
// DSOTHUMB-NEXT: 1008: 00 f0 14 e8 blx #40
|
||||
// 0x100c + 0x34 + 4 = 0x1044 = PLT func2
|
||||
// DSOTHUMB-NEXT: 100c: 00 f0 1a e8 blx #52
|
||||
// 0x1010 + 0x40 + 4 = 0x1054 = PLT func3
|
||||
// DSOTHUMB-NEXT: 1010: 00 f0 20 e8 blx #64
|
||||
// DSOARM: Disassembly of section .plt:
|
||||
// DSOARM: .plt:
|
||||
// DSOARM-NEXT: 1020: 04 e0 2d e5 str lr, [sp, #-4]!
|
||||
// DSOARM-NEXT: 1024: 04 e0 9f e5 ldr lr, [pc, #4]
|
||||
// DSOARM-NEXT: 1028: 0e e0 8f e0 add lr, pc, lr
|
||||
// DSOARM-NEXT: 102c: 08 f0 be e5 ldr pc, [lr, #8]!
|
||||
// DSOARM-NEXT: 1030: d0 1f 00 00
|
||||
// 0x1028 + 8 + 1fd0 = 0x3000
|
||||
// DSOARM-NEXT: 1034: 04 c0 9f e5 ldr r12, [pc, #4]
|
||||
// DSOARM-NEXT: 1038: 0f c0 8c e0 add r12, r12, pc
|
||||
// DSOARM-NEXT: 103c: 00 f0 9c e5 ldr pc, [r12]
|
||||
// DSOARM-NEXT: 1040: cc 1f 00 00
|
||||
// 0x1038 + 8 + 1fcc = 0x300c
|
||||
// DSOARM-NEXT: 1044: 04 c0 9f e5 ldr r12, [pc, #4]
|
||||
// DSOARM-NEXT: 1048: 0f c0 8c e0 add r12, r12, pc
|
||||
// DSOARM-NEXT: 104c: 00 f0 9c e5 ldr pc, [r12]
|
||||
// DSOARM-NEXT: 1050: c0 1f 00 00
|
||||
// 0x1048 + 8 + 1fc0 = 0x3010
|
||||
// DSOARM-NEXT: 1054: 04 c0 9f e5 ldr r12, [pc, #4]
|
||||
// DSOARM-NEXT: 1058: 0f c0 8c e0 add r12, r12, pc
|
||||
// DSOARM-NEXT: 105c: 00 f0 9c e5 ldr pc, [r12]
|
||||
// DSOARM-NEXT: 1060: b4 1f 00 00
|
||||
// 0x1058 + 8 + 1fb4 = 0x3014
|
||||
|
||||
// DSOREL: Name: .got.plt
|
||||
// DSOREL-NEXT: Type: SHT_PROGBITS
|
||||
// DSOREL-NEXT: Flags [
|
||||
// DSOREL-NEXT: SHF_ALLOC
|
||||
// DSOREL-NEXT: SHF_WRITE
|
||||
// DSOREL-NEXT: ]
|
||||
// DSOREL-NEXT: Address: 0x3000
|
||||
// DSOREL-NEXT: Offset:
|
||||
// DSOREL-NEXT: Size: 24
|
||||
// DSOREL-NEXT: Link:
|
||||
// DSOREL-NEXT: Info:
|
||||
// DSOREL-NEXT: AddressAlignment: 4
|
||||
// DSOREL-NEXT: EntrySize:
|
||||
// DSOREL: Relocations [
|
||||
// DSOREL-NEXT: Section (4) .rel.plt {
|
||||
// DSOREL-NEXT: 0x300C R_ARM_JUMP_SLOT func1 0x0
|
||||
// DSOREL-NEXT: 0x3010 R_ARM_JUMP_SLOT func2 0x0
|
||||
// DSOREL-NEXT: 0x3014 R_ARM_JUMP_SLOT func3 0x0
|
Loading…
x
Reference in New Issue
Block a user