Skip to content

Commit

Permalink
[ARM] Implement relocations: R_ARM_REL32, R_ARM_THM_JUMP11, R_ARM_PREL31
Browse files Browse the repository at this point in the history
Test case for every relocation is added.

Differential Revision: http://reviews.llvm.org/D7565

llvm-svn: 232464
  • Loading branch information
Denis Protivensky committed Mar 17, 2015
1 parent b326765 commit e458ab4
Show file tree
Hide file tree
Showing 4 changed files with 367 additions and 1 deletion.
82 changes: 81 additions & 1 deletion lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
Expand Up @@ -70,6 +70,13 @@ static Reference::Addend readAddend_ARM_CALL(const uint8_t *location) {
return llvm::SignExtend64<26>(result);
}

static Reference::Addend readAddend_THM_JUMP11(const uint8_t *location) {
const auto value = read16le(location);
const uint16_t imm11 = value & 0x7FF;

return llvm::SignExtend32<12>(imm11 << 1);
}

static Reference::Addend readAddend(const uint8_t *location,
Reference::KindValue kindValue) {
switch (kindValue) {
Expand All @@ -78,6 +85,8 @@ static Reference::Addend readAddend(const uint8_t *location,
case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
return readAddend_THM_CALL(location);
case R_ARM_THM_JUMP11:
return readAddend_THM_JUMP11(location);
case R_ARM_CALL:
case R_ARM_JUMP24:
return readAddend_ARM_CALL(location);
Expand Down Expand Up @@ -107,6 +116,12 @@ static inline void applyThmReloc(uint8_t *location, uint16_t resHi,
write16le(location, (read16le(location) & ~maskLo) | (resLo & maskLo));
}

static inline void applyThumb16Reloc(uint8_t *location, uint16_t result,
uint16_t mask = 0xFFFF) {
assert(!(result & ~mask));
write16le(location, (read16le(location) & ~mask) | (result & mask));
}

/// \brief R_ARM_ABS32 - (S + A) | T
static void relocR_ARM_ABS32(uint8_t *location, uint64_t P, uint64_t S,
int64_t A, bool addressesThumb) {
Expand All @@ -123,6 +138,42 @@ static void relocR_ARM_ABS32(uint8_t *location, uint64_t P, uint64_t S,
applyArmReloc(location, result);
}

/// \brief R_ARM_REL32 - ((S + A) | T) - P
static void relocR_ARM_REL32(uint8_t *location, uint64_t P, uint64_t S,
int64_t A, bool addressesThumb) {
uint64_t T = addressesThumb;
uint32_t result = (uint32_t)(((S + A) | T) - P);

DEBUG_WITH_TYPE(
"ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
applyArmReloc(location, result);
}

/// \brief R_ARM_PREL31 - ((S + A) | T) - P
static void relocR_ARM_PREL31(uint8_t *location, uint64_t P, uint64_t S,
int64_t A, bool addressesThumb) {
uint64_t T = addressesThumb;
uint32_t result = (uint32_t)(((S + A) | T) - P);
const uint32_t mask = 0x7FFFFFFF;
uint32_t rel31 = result & mask;

DEBUG_WITH_TYPE(
"ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
llvm::dbgs() << " result: 0x" << Twine::utohexstr(result);
llvm::dbgs() << " rel31: 0x" << Twine::utohexstr(rel31) << "\n");

applyArmReloc(location, rel31, mask);
}

/// \brief Relocate B/BL instructions. useJs defines whether J1 & J2 are used
static void relocR_ARM_THM_B_L(uint8_t *location, uint32_t result, bool useJs) {
result = (result & 0x01FFFFFE) >> 1;
Expand Down Expand Up @@ -183,6 +234,24 @@ static void relocR_ARM_THM_JUMP24(uint8_t *location, uint64_t P, uint64_t S,
relocR_ARM_THM_B_L(location, result, true);
}

/// \brief R_ARM_THM_JUMP11 - S + A - P
static void relocR_ARM_THM_JUMP11(uint8_t *location, uint64_t P, uint64_t S,
int64_t A) {
uint32_t result = (uint32_t)(S + A - P);

DEBUG_WITH_TYPE(
"ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");

//we cut off first bit because it is always 1 according to p. 4.5.3
result = (result & 0x0FFE) >> 1;

applyThumb16Reloc(location, result, 0x7FF);
}

/// \brief R_ARM_CALL - ((S + A) | T) - P
static void relocR_ARM_CALL(uint8_t *location, uint64_t P, uint64_t S,
int64_t A, bool addressesThumb) {
Expand Down Expand Up @@ -274,7 +343,7 @@ static void relocR_ARM_THM_MOV(uint8_t *location, uint32_t result) {
const uint16_t bitI = (result >> 11) & 0x1;
const uint16_t resHi = (bitI << 10) | imm4;

applyThmReloc(location, resHi, resLo, 0x40F, 0x70FF);
applyThmReloc(location, resHi, resLo, 0x40F, 0x70FF);
}

/// \brief R_ARM_THM_MOVW_ABS_NC - (S + A) | T
Expand Down Expand Up @@ -340,6 +409,10 @@ std::error_code ARMTargetRelocationHandler::applyRelocation(
relocR_ARM_ABS32(location, relocVAddress, targetVAddress, addend,
addressesThumb);
break;
case R_ARM_REL32:
relocR_ARM_REL32(location, relocVAddress, targetVAddress, addend,
addressesThumb);
break;
case R_ARM_THM_CALL:
// TODO: consider adding bool variable to disable J1 & J2 for archs
// before ARMv6
Expand All @@ -358,6 +431,9 @@ std::error_code ARMTargetRelocationHandler::applyRelocation(
relocR_ARM_THM_JUMP24(location, relocVAddress, targetVAddress, addend,
addressesThumb);
break;
case R_ARM_THM_JUMP11:
relocR_ARM_THM_JUMP11(location, relocVAddress, targetVAddress, addend);
break;
case R_ARM_MOVW_ABS_NC:
relocR_ARM_MOVW_ABS_NC(location, relocVAddress, targetVAddress, addend,
addressesThumb);
Expand All @@ -372,6 +448,10 @@ std::error_code ARMTargetRelocationHandler::applyRelocation(
case R_ARM_THM_MOVT_ABS:
relocR_ARM_THM_MOVT_ABS(location, relocVAddress, targetVAddress, addend);
break;
case R_ARM_PREL31:
relocR_ARM_PREL31(location, relocVAddress, targetVAddress, addend,
addressesThumb);
break;
default:
return make_unhandled_reloc_error();
}
Expand Down
48 changes: 48 additions & 0 deletions lld/test/elf/ARM/rel-arm-prel31.test
@@ -0,0 +1,48 @@
# Check handling of R_ARM_PREL31 relocation.
# RUN: yaml2obj -format=elf %s > %t-o.o
# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
# RUN: --noinhibit-exec %t-o.o -o %t
# RUN: llvm-objdump -s -t %t | FileCheck %s

# CHECK: Contents of section .ARM.extab:
# CHECK: 4000a4 b1ffff7f
# CHECK: SYMBOL TABLE:
# CHECK: 00000000 *UND* 00000000
# CHECK: 00400054 g F .text 00000050 __gxx_personality_v0

---
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_ARM
Flags: [ EF_ARM_EABI_VER5 ]
Sections:
- Name: .ARM.extab
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
AddressAlign: 0x4
Content: 0000000084019701B0B0B008FFFF01080E2432003A040000
- Name: .rel.ARM.extab
Type: SHT_REL
Link: .symtab
AddressAlign: 0x4
Info: .ARM.extab
Relocations:
- Offset: 0
Symbol: __gxx_personality_v0
Type: R_ARM_PREL31
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
AddressAlign: 0x4
Content: 80B400AF00231846BD465DF8047B704780B582B000AF3B1D1846FFF7FEFFFFF7FEFFFFF7FEFF0420FFF7FEFF0346184601230360002240F20001C0F20001FFF7FEFF3B1D1846FFF7FEFFFFF7FEFF00BF
Symbols:
Local:
Global:
- Name: __gxx_personality_v0
Type: STT_FUNC
Section: .text
Value: 0x1
...

97 changes: 97 additions & 0 deletions lld/test/elf/ARM/rel-rel32.test
@@ -0,0 +1,97 @@
# Check handling of R_ARM_REL32 relocation.
# RUN: yaml2obj -format=elf %s > %t-o.o
# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
# RUN: --noinhibit-exec %t-o.o -o %t
# RUN: llvm-objdump -s -t %t | FileCheck %s

# CHECK: Contents of section .text:
# CHECK-NEXT: 400074 80b400af 880f0000
# CHECK: SYMBOL TABLE:
# CHECK: 00400074 g F .text 00000004 main
# CHECK: 00401000 g .bss 00000004 _myref

---
---
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_ARM
Flags: [ EF_ARM_EABI_VER5 ]
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
AddressAlign: 0x0000000000000004
Content: 80B400AF0000000000231846BD465DF8047B7047
- Name: .rel.text
Type: SHT_REL
Link: .symtab
AddressAlign: 0x0000000000000004
Info: .text
Relocations:
- Offset: 0x0000000000000004
Symbol: _myref
Type: R_ARM_REL32
- Name: .data
Type: SHT_PROGBITS
Flags: [ SHF_WRITE, SHF_ALLOC ]
AddressAlign: 0x0000000000000001
Content: ''
- Name: .bss
Type: SHT_NOBITS
Flags: [ SHF_WRITE, SHF_ALLOC ]
AddressAlign: 0x0000000000000004
Content: '00474343'
- Name: .comment
Type: SHT_PROGBITS
Flags: [ SHF_MERGE, SHF_STRINGS ]
AddressAlign: 0x0000000000000001
Content: 004743433A202863726F7373746F6F6C2D4E47206C696E61726F2D312E31332E312D342E392D323031342E3039202D204C696E61726F2047434320342E392D323031342E30392920342E392E32203230313430393034202870726572656C656173652900
- Name: .note.GNU-stack
Type: SHT_PROGBITS
AddressAlign: 0x0000000000000001
Content: ''
- Name: .ARM.attributes
Type: SHT_ARM_ATTRIBUTES
AddressAlign: 0x0000000000000001
Content: 4134000000616561626900012A00000005372D4100060A0741080109020A041204140115011703180119011A021B031C011E062201
Symbols:
Local:
- Name: test.c
Type: STT_FILE
- Name: .text
Type: STT_SECTION
Section: .text
- Name: .data
Type: STT_SECTION
Section: .data
- Name: .bss
Type: STT_SECTION
Section: .bss
- Name: '$d'
Section: .text
Value: 0x0000000000000004
- Name: '$t'
Section: .text
Value: 0x0000000000000008
- Name: .note.GNU-stack
Type: STT_SECTION
Section: .note.GNU-stack
- Name: .comment
Type: STT_SECTION
Section: .comment
- Name: .ARM.attributes
Type: STT_SECTION
Section: .ARM.attributes
Global:
- Name: _myref
Type: STT_OBJECT
Section: .bss
Size: 0x0000000000000004
- Name: main
Type: STT_FUNC
Section: .text
Value: 0x0000000000000001
Size: 0x0000000000000014
...

0 comments on commit e458ab4

Please sign in to comment.