Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
[ELF] Support R_ARM_SBREL32 Relocation
Browse files Browse the repository at this point in the history
This change adds support for the R_ARM_SBREL32 relocation. The relocation
is a base relative relocation that is produced by clang/llvm when -frwpi
is used. The use case for the -frwpi option is position independent data
for embedded systems that do not have a GOT. With -frwpi all data is
accessed via an offset from a base register (usually r9), where r9 is set
at run time to where the data has been loaded. The base of the data is
known as the static base.

The ARM ABI defines the static base as:
B(S) is the addressing origin of the output segment defining the symbol S.
The origin is not required to be the base address of the segment. For
simplicity we choose to use the base address of the segment.

The ARM procedure call standard only defines a read write variant using
R_ARM_SBREL32 relocations. The read-only data is accessed via pc-relative
offsets from the code, this is implemented in clang as -fropi.

Fixes PR32924

Differential Revision: https://reviews.llvm.org/D33280



git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@303337 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
smithp35 committed May 18, 2017
1 parent 98da9e4 commit 29241e3
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 0 deletions.
16 changes: 16 additions & 0 deletions ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,20 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
}
}

// ARM SBREL relocations are of the form S + A - B where B is the static base
// The ARM ABI defines base to be "addressing origin of the output segment
// defining the symbol S". We defined the "addressing origin"/static base to be
// the base of the PT_LOAD segment containing the Body.
// The procedure call standard only defines a Read Write Position Independent
// RWPI variant so in practice we should expect the static base to be the base
// of the RW segment.
static uint64_t getARMStaticBase(const SymbolBody &Body) {
OutputSection *OS = Body.getOutputSection();
if (!OS || !OS->FirstInPtLoad)
fatal("SBREL relocation to " + Body.getName() + " without static base\n");
return OS->FirstInPtLoad->Addr;
}

template <class ELFT>
static typename ELFT::uint
getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P,
Expand All @@ -398,6 +412,8 @@ getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P,
case R_ABS:
case R_RELAX_GOT_PC_NOPIC:
return Body.getVA(A);
case R_ARM_SBREL:
return Body.getVA(A) - getARMStaticBase(Body);
case R_GOT:
case R_RELAX_TLS_GD_TO_IE_ABS:
return Body.getGotVA() + A;
Expand Down
1 change: 1 addition & 0 deletions ELF/Relocations.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class OutputSection;
// doesn't have to know about architecture-specific details.
enum RelExpr {
R_ABS,
R_ARM_SBREL,
R_GOT,
R_GOTONLY_PC,
R_GOTONLY_PC_FROM_END,
Expand Down
3 changes: 3 additions & 0 deletions ELF/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1693,6 +1693,8 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
case R_ARM_TLS_IE32:
// GOT(S) + A - P
return R_GOT_PC;
case R_ARM_SBREL32:
return R_ARM_SBREL;
case R_ARM_TARGET1:
return Config->Target1Rel ? R_PC : R_ABS;
case R_ARM_TARGET2:
Expand Down Expand Up @@ -1832,6 +1834,7 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
case R_ARM_GOT_PREL:
case R_ARM_REL32:
case R_ARM_RELATIVE:
case R_ARM_SBREL32:
case R_ARM_TARGET1:
case R_ARM_TARGET2:
case R_ARM_TLS_GD32:
Expand Down
39 changes: 39 additions & 0 deletions test/ELF/arm-sbrel32.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
// REQUIRES: arm

// Test the R_ARM_SBREL32 relocation which calculates the offset of the Symbol
// from the static base. We define the static base to be the address of the
// segment containing the symbol
.text
.syntax unified

.globl _start
.p2align 2
.type _start,%function
_start:
.fnstart
bx lr

.long foo(sbrel)
.long foo2(sbrel)
.long foo3(sbrel)
.long foo4(sbrel)
// RW segment starts here
.data
.p2align 4
foo: .word 10
foo2: .word 20

.bss
foo3: .space 4
foo4: .space 4

// CHECK: Disassembly of section .text:
// CHECK-NEXT: _start:
// CHECK-NEXT: 11000: 1e ff 2f e1 bx lr
// CHECK: 11004: 00 00 00 00 .word 0x00000000
// CHECK-NEXT: 11008: 04 00 00 00 .word 0x00000004
// CHECK-NEXT: 1100c: 08 00 00 00 .word 0x00000008
// CHECK-NEXT: 11010: 0c 00 00 00 .word 0x0000000c

0 comments on commit 29241e3

Please sign in to comment.