mirror of
https://github.com/intel/llvm.git
synced 2026-02-07 07:39:11 +08:00
[ELF][MIPS] Make R_MIPS_LO16 a relative relocation if it references _gp_disp symbol
The _gp_disp symbol designates offset between start of function and 'gp' pointer into GOT. The following code is a typical MIPS function preamble used to setup $gp register: lui $gp, %hi(_gp_disp) addi $gp, $gp, %lo(_gp_disp) To calculate R_MIPS_HI16 / R_MIPS_LO16 relocations results we use the following formulas: %hi(_gp - P + A) %lo(_gp - P + A + 4), where _gp is a value of _gp symbol, A is addend, and P current address. The R_MIPS_LO16 relocation references _gp_disp symbol is always the second instruction. That is why we need four byte adjustments. The patch assigns R_PC type for R_MIPS_LO16 relocation and adjusts its addend by 4. That fix R_MIPS_LO16 calculation. For details see p. 4-19 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf Differential Revision: http://reviews.llvm.org/D19115 llvm-svn: 266368
This commit is contained in:
@@ -1579,6 +1579,7 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
|
||||
default:
|
||||
return R_ABS;
|
||||
case R_MIPS_HI16:
|
||||
case R_MIPS_LO16:
|
||||
// MIPS _gp_disp designates offset between start of function and 'gp'
|
||||
// pointer into GOT. __gnu_local_gp is equal to the current value of
|
||||
// the 'gp'. Therefore any relocations against them do not require
|
||||
|
||||
@@ -462,14 +462,22 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||
if (auto *S = dyn_cast<SharedSymbol<ELFT>>(&Body))
|
||||
S->File->IsUsed = true;
|
||||
|
||||
RelExpr Expr = Target->getRelExpr(Type, Body);
|
||||
uintX_t Addend = getAddend<ELFT>(RI);
|
||||
const uint8_t *BufLoc = Buf + RI.r_offset;
|
||||
if (!RelTy::IsRela)
|
||||
Addend += Target->getImplicitAddend(BufLoc, Type);
|
||||
if (Config->EMachine == EM_MIPS)
|
||||
if (Config->EMachine == EM_MIPS) {
|
||||
Addend += findMipsPairedAddend<ELFT>(Buf, BufLoc, Body, &RI, E);
|
||||
if (Type == R_MIPS_LO16 && Expr == R_PC)
|
||||
// R_MIPS_LO16 expression has R_PC type iif the target is _gp_disp
|
||||
// symbol. In that case we should use the following formula for
|
||||
// calculation "AHL + GP – P + 4". Let's add 4 right here.
|
||||
// For details see p. 4-19 at
|
||||
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
||||
Addend += 4;
|
||||
}
|
||||
|
||||
RelExpr Expr = Target->getRelExpr(Type, Body);
|
||||
if (unsigned Processed =
|
||||
handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) {
|
||||
I += (Processed - 1);
|
||||
|
||||
@@ -16,6 +16,9 @@ __start:
|
||||
lui $t0,%hi(_gp_disp)
|
||||
addi $t0,$t0,%lo(_gp_disp)
|
||||
lw $v0,%call16(_foo)($gp)
|
||||
bar:
|
||||
lui $t0,%hi(_gp_disp)
|
||||
addi $t0,$t0,%lo(_gp_disp)
|
||||
|
||||
# EXE: Disassembly of section .text:
|
||||
# EXE-NEXT: __start:
|
||||
@@ -23,11 +26,16 @@ __start:
|
||||
# ^-- %hi(0x37ff0-0x20000)
|
||||
# EXE-NEXT: 20004: 21 08 7f f0 addi $8, $8, 32752
|
||||
# ^-- %lo(0x37ff0-0x20004+4)
|
||||
# EXE: bar:
|
||||
# EXE-NEXT: 2000c: 3c 08 00 01 lui $8, 1
|
||||
# ^-- %hi(0x37ff0-0x2000c)
|
||||
# EXE-NEXT: 20010: 21 08 7f e4 addi $8, $8, 32740
|
||||
# ^-- %lo(0x37ff0-0x20010+4)
|
||||
|
||||
# EXE: SYMBOL TABLE:
|
||||
# EXE: 0002000c .text 00000000 bar
|
||||
# EXE: 00037ff0 .got 00000000 .hidden _gp
|
||||
# EXE: 00020000 .text 00000000 __start
|
||||
# EXE: 00020010 .text 00000000 _foo
|
||||
|
||||
# SO: Disassembly of section .text:
|
||||
# SO-NEXT: __start:
|
||||
@@ -35,8 +43,13 @@ __start:
|
||||
# ^-- %hi(0x27ff0-0x10000)
|
||||
# SO-NEXT: 10004: 21 08 7f f0 addi $8, $8, 32752
|
||||
# ^-- %lo(0x27ff0-0x10004+4)
|
||||
# SO: bar:
|
||||
# SO-NEXT: 1000c: 3c 08 00 01 lui $8, 1
|
||||
# ^-- %hi(0x27ff0-0x1000c)
|
||||
# SO-NEXT: 10010: 21 08 7f e4 addi $8, $8, 32740
|
||||
# ^-- %lo(0x27ff0-0x10010+4)
|
||||
|
||||
# SO: SYMBOL TABLE:
|
||||
# SO: 0001000c .text 00000000 bar
|
||||
# SO: 00027ff0 .got 00000000 .hidden _gp
|
||||
# SO: 00010000 .text 00000000 __start
|
||||
# SO: 00010010 .text 00000000 _foo
|
||||
|
||||
Reference in New Issue
Block a user