diff options
-rw-r--r-- | lld/ELF/Config.h | 1 | ||||
-rw-r--r-- | lld/ELF/Driver.cpp | 1 | ||||
-rw-r--r-- | lld/ELF/InputSection.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 2 | ||||
-rw-r--r-- | lld/test/ELF/mips-gp-local.s | 20 |
5 files changed, 25 insertions, 1 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index e9113aca180..6571807f0df 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -37,6 +37,7 @@ enum ELFKind { struct Configuration { SymbolBody *EntrySym = nullptr; SymbolBody *MipsGpDisp = nullptr; + SymbolBody *MipsLocalGp = nullptr; InputFile *FirstElf = nullptr; llvm::StringRef DynamicLinker; llvm::StringRef Entry; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index a417204ed08..3bb90537026 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -328,6 +328,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // start of function and gp pointer into GOT. Use 'strong' variant of // the addIgnored to prevent '_gp_disp' substitution. Config->MipsGpDisp = Symtab.addIgnored("_gp_disp"); + Config->MipsLocalGp = Symtab.addIgnored("__gnu_local_gp"); // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer // so that it points to an absolute address which is relative to GOT. diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 61170c43209..1d729684fec 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -234,6 +234,8 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd, SymVA = getMipsGpAddr<ELFT>() - AddrLoc; else if (Type == R_MIPS_LO16 && Body == Config->MipsGpDisp) SymVA = getMipsGpAddr<ELFT>() - AddrLoc + 4; + else if (Body == Config->MipsLocalGp) + SymVA = getMipsGpAddr<ELFT>(); } uintX_t Size = Body->getSize<ELFT>(); Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + A, Size + A, diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index e4fb84f72af..c184d755dc0 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -388,7 +388,7 @@ void Writer<ELFT>::scanRelocs( // relocation too because that case is possible for executable file // linking only. continue; - if (Body == Config->MipsGpDisp) + if (Body == Config->MipsGpDisp || Body == Config->MipsLocalGp) // MIPS _gp_disp designates offset between start of function and gp // pointer into GOT therefore any relocations against it do not require // dynamic relocation. diff --git a/lld/test/ELF/mips-gp-local.s b/lld/test/ELF/mips-gp-local.s new file mode 100644 index 00000000000..0ca8ec3b483 --- /dev/null +++ b/lld/test/ELF/mips-gp-local.s @@ -0,0 +1,20 @@ +# Check handling of relocations against __gnu_local_gp symbol. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: ld.lld -o %t.exe %t.o +# RUN: llvm-objdump -d -t %t.exe | FileCheck %s + +# REQUIRES: mips + +# CHECK: Disassembly of section .text: +# CHECK-NEXT: __start: +# CHECK-NEXT: 20000: 3c 08 00 00 lui $8, 0 +# CHECK-NEXT: 20004: 21 08 00 00 addi $8, $8, 0 + +# CHECK: 00000000 *ABS* 00000000 _gp + + .text + .globl __start +__start: + lui $t0,%hi(__gnu_local_gp) + addi $t0,$t0,%lo(__gnu_local_gp) |