diff options
-rw-r--r-- | lld/ELF/Driver.cpp | 5 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.cpp | 7 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.h | 1 | ||||
-rw-r--r-- | lld/ELF/Symbols.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/Symbols.h | 7 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 3 | ||||
-rw-r--r-- | lld/test/ELF/Inputs/mips-gp-disp-def.s | 8 | ||||
-rw-r--r-- | lld/test/ELF/mips-gp-disp.s | 33 |
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) |