[ELF][MIPS] Handle R_MIPS_HI16/LO16 relocations against _gp_disp symbol
The `_gp_disp` is a magic symbol designates offset between start of
function and gp pointer into GOT. Only `R_MIPS_HI16` and `R_MIPS_LO16`
relocations are permitted with `_gp_disp`. The patch adds the `_gp_disp`
as an ignored symbol and adjusts symbol value before call the `relocateOne`
for `R_MIPS_HI16/LO16` relocations.
Differential Revision: http://reviews.llvm.org/D15480
llvm-svn: 255768
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 299a0df..7b820f1 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -32,6 +32,7 @@
struct Configuration {
SymbolBody *EntrySym = nullptr;
+ SymbolBody *MipsGpDisp = nullptr;
InputFile *FirstElf = nullptr;
llvm::StringRef DynamicLinker;
llvm::StringRef Entry;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index f1e1abe..048ff10 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -263,6 +263,11 @@
Symtab.addIgnoredSym("_GLOBAL_OFFSET_TABLE_");
}
+ // On MIPS O32 ABI _gp_disp is a magic symbol designates offset between
+ // start of function and gp pointer into GOT.
+ if (Config->EMachine == EM_MIPS)
+ Config->MipsGpDisp = Symtab.addIgnoredSym("_gp_disp");
+
if (!Config->Entry.empty()) {
// Set either EntryAddr (if S is a number) or EntrySym (otherwise).
StringRef S = Config->Entry;
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index f449e70..0a17528 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -205,6 +205,11 @@
} else if (Target->isTlsDynReloc(Type) ||
Target->isSizeDynReloc(Type, Body)) {
continue;
+ } else if (Config->EMachine == EM_MIPS) {
+ if (Type == R_MIPS_HI16 && &Body == Config->MipsGpDisp)
+ SymVA = getMipsGpAddr<ELFT>() - AddrLoc;
+ else if (Type == R_MIPS_LO16 && &Body == Config->MipsGpDisp)
+ SymVA = getMipsGpAddr<ELFT>() - AddrLoc + 4;
}
uintX_t A = getAddend<ELFT>(RI);
uintX_t Size = getSymSize<ELFT>(Body);
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index 6e4f55a..4c66f02 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -88,10 +88,12 @@
resolve(Sym);
}
-template <class ELFT> void SymbolTable<ELFT>::addIgnoredSym(StringRef Name) {
+template <class ELFT>
+SymbolBody *SymbolTable<ELFT>::addIgnoredSym(StringRef Name) {
auto Sym = new (Alloc)
DefinedAbsolute<ELFT>(Name, DefinedAbsolute<ELFT>::IgnoreUndef);
resolve(Sym);
+ return Sym;
}
template <class ELFT> bool SymbolTable<ELFT>::isUndefined(StringRef Name) {
diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h
index a778aab..44726ef 100644
--- a/lld/ELF/SymbolTable.h
+++ b/lld/ELF/SymbolTable.h
@@ -54,7 +54,7 @@
typename llvm::object::ELFFile<ELFT>::Elf_Sym &ESym);
void addSyntheticSym(StringRef Name, OutputSectionBase<ELFT> &Section,
typename llvm::object::ELFFile<ELFT>::uintX_t Value);
- void addIgnoredSym(StringRef Name);
+ SymbolBody *addIgnoredSym(StringRef Name);
bool isUndefined(StringRef Name);
void scanShlibUndefined();
SymbolBody *find(StringRef Name);
diff --git a/lld/test/ELF/mips-hilo-gp-disp.s b/lld/test/ELF/mips-hilo-gp-disp.s
new file mode 100644
index 0000000..e2e9ae7
--- /dev/null
+++ b/lld/test/ELF/mips-hilo-gp-disp.s
@@ -0,0 +1,42 @@
+# Check R_MIPS_HI16 / LO16 relocations calculation against _gp_disp.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck -check-prefix=EXE %s
+# RUN: ld.lld %t1.o %t2.o -shared -o %t.so
+# RUN: llvm-objdump -d -t %t.so | FileCheck -check-prefix=SO %s
+
+# REQUIRES: mips
+
+ .text
+ .globl __start
+__start:
+ lui $t0,%hi(_gp_disp)
+ addi $t0,$t0,%lo(_gp_disp)
+ lw $v0,%call16(_foo)($gp)
+
+# EXE: Disassembly of section .text:
+# EXE-NEXT: __start:
+# EXE-NEXT: 20000: 3c 08 00 01 lui $8, 1
+# ^-- %hi(0x37ff0-0x20000)
+# EXE-NEXT: 20004: 21 08 7f f0 addi $8, $8, 32752
+# ^-- %lo(0x37ff0-0x20004+4)
+
+# EXE: SYMBOL TABLE:
+# EXE: 00037ff0 *ABS* 00000000 _gp
+# EXE: 00020000 .text 00000000 __start
+# EXE: 00020010 .text 00000000 _foo
+
+# SO: Disassembly of section .text:
+# SO-NEXT: __start:
+# SO-NEXT: 10000: 3c 08 00 01 lui $8, 1
+# ^-- %hi(0x27ff0-0x10000)
+# SO-NEXT: 10004: 21 08 7f f0 addi $8, $8, 32752
+# ^-- %lo(0x27ff0-0x10004+4)
+
+# SO: SYMBOL TABLE:
+# SO: 00027ff0 *ABS* 00000000 _gp
+# SO: 00010000 .text 00000000 __start
+# SO: 00010010 .text 00000000 _foo