Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -304,8 +304,9 @@ 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. Index: lld/trunk/ELF/SymbolTable.h =================================================================== --- lld/trunk/ELF/SymbolTable.h +++ lld/trunk/ELF/SymbolTable.h @@ -55,6 +55,7 @@ SymbolBody *addSynthetic(StringRef Name, OutputSectionBase &Section, uintX_t Value); SymbolBody *addIgnored(StringRef Name); + SymbolBody *addIgnoredStrong(StringRef Name); void scanShlibUndefined(); SymbolBody *find(StringRef Name); Index: lld/trunk/ELF/SymbolTable.cpp =================================================================== --- lld/trunk/ELF/SymbolTable.cpp +++ lld/trunk/ELF/SymbolTable.cpp @@ -123,6 +123,13 @@ return addAbsolute(Name, ElfSym::IgnoreUndef); } +// The 'strong' variant of the addIgnored. Adds symbol which has a global +// binding and cannot be substituted. +template +SymbolBody *SymbolTable::addIgnoredStrong(StringRef Name) { + return addAbsolute(Name, ElfSym::IgnoreUndefStrong); +} + // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. // Used to implement --wrap. template void SymbolTable::wrap(StringRef Name) { Index: lld/trunk/ELF/Symbols.h =================================================================== --- lld/trunk/ELF/Symbols.h +++ lld/trunk/ELF/Symbols.h @@ -300,8 +300,11 @@ typedef typename llvm::object::ELFFile::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 typename ElfSym::Elf_Sym ElfSym::IgnoreUndef; +template +typename ElfSym::Elf_Sym ElfSym::IgnoreUndefStrong; template typename ElfSym::Elf_Sym ElfSym::End; template typename ElfSym::Elf_Sym ElfSym::MipsGp; template Index: lld/trunk/ELF/Symbols.cpp =================================================================== --- lld/trunk/ELF/Symbols.cpp +++ lld/trunk/ELF/Symbols.cpp @@ -122,6 +122,8 @@ ElfSym::End.setBinding(STB_GLOBAL); ElfSym::IgnoreUndef.setBinding(STB_WEAK); ElfSym::IgnoreUndef.setVisibility(STV_HIDDEN); + ElfSym::IgnoreUndefStrong.setBinding(STB_GLOBAL); + ElfSym::IgnoreUndefStrong.setVisibility(STV_HIDDEN); } void elf2::initSymbols() { Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -599,7 +599,8 @@ // Don't include synthetic symbols like __init_array_start in every output. if (auto *U = dyn_cast>(&B)) - if (&U->Sym == &ElfSym::IgnoreUndef) + if (&U->Sym == &ElfSym::IgnoreUndef || + &U->Sym == &ElfSym::IgnoreUndefStrong) return false; return true; Index: lld/trunk/test/ELF/Inputs/mips-gp-disp-def.s =================================================================== --- lld/trunk/test/ELF/Inputs/mips-gp-disp-def.s +++ lld/trunk/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 Index: lld/trunk/test/ELF/mips-gp-disp.s =================================================================== --- lld/trunk/test/ELF/mips-gp-disp.s +++ lld/trunk/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)