From 597df21eb2385776cd4f015223b34bf81b45610e Mon Sep 17 00:00:00 2001 From: Simon Atanasyan Date: Thu, 4 Feb 2016 12:09:49 +0000 Subject: [PATCH] [ELF][MIPS] Add handling for __gnu_local_gp symbol This symbol is a "fake" symbol like "_gp_disp" and denotes the GOT + 0x7FF0 value. llvm-svn: 259781 --- lld/ELF/Config.h | 1 + lld/ELF/Driver.cpp | 1 + lld/ELF/InputSection.cpp | 2 ++ lld/ELF/Writer.cpp | 2 +- lld/test/ELF/mips-gp-local.s | 20 ++++++++++++++++++++ 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 lld/test/ELF/mips-gp-local.s diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index e9113ac..6571807 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 a417204..3bb9053 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -328,6 +328,7 @@ template 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 61170c4..1d72968 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -234,6 +234,8 @@ void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd, SymVA = getMipsGpAddr() - AddrLoc; else if (Type == R_MIPS_LO16 && Body == Config->MipsGpDisp) SymVA = getMipsGpAddr() - AddrLoc + 4; + else if (Body == Config->MipsLocalGp) + SymVA = getMipsGpAddr(); } uintX_t Size = Body->getSize(); Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + A, Size + A, diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index e4fb84f..c184d75 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -388,7 +388,7 @@ void Writer::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 0000000..0ca8ec3 --- /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) -- 2.7.4