diff options
-rw-r--r-- | lld/ELF/Target.cpp | 1 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 12 | ||||
-rw-r--r-- | lld/test/ELF/mips-hilo-gp-disp.s | 17 |
3 files changed, 26 insertions, 4 deletions
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 8b12d751771..240eb983c5a 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -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 diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 31f2d3e2dcd..7a75d234396 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -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); diff --git a/lld/test/ELF/mips-hilo-gp-disp.s b/lld/test/ELF/mips-hilo-gp-disp.s index 65368ac5083..37cf90d9728 100644 --- a/lld/test/ELF/mips-hilo-gp-disp.s +++ b/lld/test/ELF/mips-hilo-gp-disp.s @@ -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 |