Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -220,6 +220,9 @@ if (Files.empty()) error("no input files."); + + if (Config->GnuHash && Config->EMachine == EM_MIPS) + error("The .gnu.hash section is not compatible with the MIPS target."); } template void LinkerDriver::link(opt::InputArgList &Args) { Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -1081,6 +1081,17 @@ Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; } +// Orders symbols according to their positions in the GOT, +// in compliance with MIPS ABI rules. +// See "Global Offset Table" in Chapter 5 in the following document +// for detailed description: +// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf +static bool sortMipsSymbols(SymbolBody *L, SymbolBody *R) { + if (!L->isInGot() || !R->isInGot()) + return R->isInGot(); + return L->GotIndex < R->GotIndex; +} + template void SymbolTableSection::finalize() { if (this->Header.sh_size) return; // Already finalized. @@ -1100,6 +1111,8 @@ if (Out::GnuHashTab) // NB: It also sorts Symbols to meet the GNU hash table requirements. Out::GnuHashTab->addSymbols(Symbols); + else if (Config->EMachine == EM_MIPS) + std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); size_t I = 0; for (SymbolBody *B : Symbols) B->setDynamicSymbolTableIndex(++I); Index: lld/trunk/test/elf2/mips-dynsym-sort.s =================================================================== --- lld/trunk/test/elf2/mips-dynsym-sort.s +++ lld/trunk/test/elf2/mips-dynsym-sort.s @@ -0,0 +1,43 @@ +# Check the order of dynamic symbols for the MIPS target. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o +# RUN: ld.lld2 -shared %t-be.o -o %t-be.so +# RUN: llvm-readobj -symbols -dyn-symbols %t-be.so | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o +# RUN: ld.lld2 -shared %t-el.o -o %t-el.so +# RUN: llvm-readobj -symbols -dyn-symbols %t-el.so | FileCheck %s + +# REQUIRES: mips + + .data + .globl v1,v2,v3 +v1: + .space 4 +v2: + .space 4 +v3: + .space 4 + + .text + .globl __start +__start: + lui $2, %got(v3) # v3 will precede v1 in the GOT + lui $2, %got(v1) + +# Since all these symbols have global binding, +# the Symbols section contains them in the original order. +# CHECK: Symbols [ +# CHECK: Name: v1 +# CHECK: Name: v2 +# CHECK: Name: v3 +# CHECK: ] + +# The symbols in the DynamicSymbols section are sorted in compliance with +# the MIPS rules. v2 comes first as it is not in the GOT. +# v1 and v3 are sorted according to their order in the GOT. +# CHECK: DynamicSymbols [ +# CHECK: Name: v2@ +# CHECK: Name: v3@ +# CHECK: Name: v1@ +# CHECK: ] Index: lld/trunk/test/elf2/mips-gnu-hash.s =================================================================== --- lld/trunk/test/elf2/mips-gnu-hash.s +++ lld/trunk/test/elf2/mips-gnu-hash.s @@ -0,0 +1,15 @@ +# Shouldn't allow the GNU hash style to be selected with the MIPS target. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o +# RUN: not ld.lld2 -shared -hash-style=gnu %t-be.o -o %t-be.so 2>&1 | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o +# RUN: not ld.lld2 -shared -hash-style=gnu %t-el.o -o %t-el.so 2>&1 | FileCheck %s + +# CHECK: The .gnu.hash section is not compatible with the MIPS target. + +# REQUIRES: mips + + .globl __start +__start: + nop