summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Driver.cpp5
-rw-r--r--lld/ELF/SymbolTable.cpp7
-rw-r--r--lld/ELF/SymbolTable.h1
-rw-r--r--lld/ELF/Symbols.cpp2
-rw-r--r--lld/ELF/Symbols.h7
-rw-r--r--lld/ELF/Writer.cpp3
-rw-r--r--lld/test/ELF/Inputs/mips-gp-disp-def.s8
-rw-r--r--lld/test/ELF/mips-gp-disp.s33
8 files changed, 62 insertions, 4 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index ea1a51cc98b..f00d97851e4 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -304,8 +304,9 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (Config->EMachine == EM_MIPS) {
// On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
- // start of function and gp pointer into GOT.
- Config->MipsGpDisp = Symtab.addIgnored("_gp_disp");
+ // start of function and gp pointer into GOT. Use 'strong' variant of
+ // the addIgnored to prevent '_gp_disp' substitution.
+ Config->MipsGpDisp = Symtab.addIgnoredStrong("_gp_disp");
// 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/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index 7825e64784d..a66bb04df3e 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -123,6 +123,13 @@ SymbolBody *SymbolTable<ELFT>::addIgnored(StringRef Name) {
return addAbsolute(Name, ElfSym<ELFT>::IgnoreUndef);
}
+// The 'strong' variant of the addIgnored. Adds symbol which has a global
+// binding and cannot be substituted.
+template <class ELFT>
+SymbolBody *SymbolTable<ELFT>::addIgnoredStrong(StringRef Name) {
+ return addAbsolute(Name, ElfSym<ELFT>::IgnoreUndefStrong);
+}
+
// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
// Used to implement --wrap.
template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h
index 26cbe8ae219..16ed821bf01 100644
--- a/lld/ELF/SymbolTable.h
+++ b/lld/ELF/SymbolTable.h
@@ -55,6 +55,7 @@ public:
SymbolBody *addSynthetic(StringRef Name, OutputSectionBase<ELFT> &Section,
uintX_t Value);
SymbolBody *addIgnored(StringRef Name);
+ SymbolBody *addIgnoredStrong(StringRef Name);
void scanShlibUndefined();
SymbolBody *find(StringRef Name);
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index ba6317a4c06..6bc9e1f79ce 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -122,6 +122,8 @@ template <class ELFT> static void doInitSymbols() {
ElfSym<ELFT>::End.setBinding(STB_GLOBAL);
ElfSym<ELFT>::IgnoreUndef.setBinding(STB_WEAK);
ElfSym<ELFT>::IgnoreUndef.setVisibility(STV_HIDDEN);
+ ElfSym<ELFT>::IgnoreUndefStrong.setBinding(STB_GLOBAL);
+ ElfSym<ELFT>::IgnoreUndefStrong.setVisibility(STV_HIDDEN);
}
void elf2::initSymbols() {
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 59135bfe1f5..3eea383f8dd 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -300,8 +300,11 @@ template <class ELFT> struct ElfSym {
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
// Used to represent an undefined symbol which we don't want
- // to add to the output file's symbol table.
+ // to add to the output file's symbol table. The `IgnoreUndef`
+ // has weak binding and can be substituted. The `InoreUndefStrong`
+ // has global binding and gets priority over symbols from shared libs.
static Elf_Sym IgnoreUndef;
+ static Elf_Sym IgnoreUndefStrong;
// The content for _end and end symbols.
static Elf_Sym End;
@@ -316,6 +319,8 @@ template <class ELFT> struct ElfSym {
};
template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::IgnoreUndef;
+template <class ELFT>
+typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::IgnoreUndefStrong;
template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::End;
template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::MipsGp;
template <class ELFT>
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index b8a2f4f8007..c61db87478e 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -599,7 +599,8 @@ template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
// Don't include synthetic symbols like __init_array_start in every output.
if (auto *U = dyn_cast<DefinedRegular<ELFT>>(&B))
- if (&U->Sym == &ElfSym<ELFT>::IgnoreUndef)
+ if (&U->Sym == &ElfSym<ELFT>::IgnoreUndef ||
+ &U->Sym == &ElfSym<ELFT>::IgnoreUndefStrong)
return false;
return true;
diff --git a/lld/test/ELF/Inputs/mips-gp-disp-def.s b/lld/test/ELF/Inputs/mips-gp-disp-def.s
new file mode 100644
index 00000000000..79306df9bfc
--- /dev/null
+++ b/lld/test/ELF/Inputs/mips-gp-disp-def.s
@@ -0,0 +1,8 @@
+# We cannot create a shared library with defined _gp_disp symbol
+# so we use a workaround - create a library with XXXXXXXX symbols
+# and use 'sed' to replace it by _gp_disp right in the binary file.
+ .data
+ .globl XXXXXXXX
+ .space 16
+XXXXXXXX:
+ .space 4
diff --git a/lld/test/ELF/mips-gp-disp.s b/lld/test/ELF/mips-gp-disp.s
new file mode 100644
index 00000000000..7914a223446
--- /dev/null
+++ b/lld/test/ELF/mips-gp-disp.s
@@ -0,0 +1,33 @@
+# Check that even if _gp_disp symbol is defined in the shared library
+# we use our own value.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: %S/Inputs/mips-gp-disp-def.s -o %t-ext.o
+# RUN: ld.lld -shared -o %t-ext-int.so %t-ext.o
+# RUN: sed -e 's/XXXXXXXX/_gp_disp/g' %t-ext-int.so > %t-ext.so
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared -o %t.so %t.o %t-ext.so
+# RUN: llvm-readobj -symbols %t.so | FileCheck -check-prefix=INT-SO %s
+# RUN: llvm-readobj -symbols %t-ext.so | FileCheck -check-prefix=EXT-SO %s
+# RUN: llvm-objdump -d -t %t.so | FileCheck -check-prefix=DIS %s
+
+# REQUIRES: mips
+
+# INT-SO-NOT: Name: _gp_disp
+
+# EXT-SO: Name: _gp_disp
+# EXT-SO-NEXT: Value: 0x20010
+
+# DIS: Disassembly of section .text:
+# DIS-NEXT: __start:
+# DIS-NEXT: 10000: 3c 08 00 01 lui $8, 1
+# DIS-NEXT: 10004: 21 08 7f f0 addi $8, $8, 32752
+# ^-- 0x37ff0 & 0xffff
+# DIS: 00027ff0 *ABS* 00000000 _gp
+
+ .text
+ .globl __start
+__start:
+ lui $t0,%hi(_gp_disp)
+ addi $t0,$t0,%lo(_gp_disp)
+ lw $v0,%call16(_foo)($gp)
OpenPOWER on IntegriCloud