Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -215,13 +215,11 @@ // should be initialized by 'page address'. This address is high 16-bits // of sum the symbol's value and the addend. return Out::Got->getMipsLocalPageOffset(Body.getVA(A)); - case R_MIPS_GOT_LOCAL: - // For non-local symbols GOT entries should contain their full - // addresses. But if such symbol cannot be preempted, we do not - // have to put them into the "global" part of GOT and use dynamic - // linker to determine their actual addresses. That is why we - // create GOT entries for them in the "local" part of GOT. - return Out::Got->getMipsLocalEntryOffset(Body.getVA(A)); + case R_MIPS_GOT_OFF: + // In case of MIPS if a GOT relocation has non-zero addend this addend + // should be applied to the GOT entry content not to the GOT entry offset. + // That is why we use separate expression type. + return Out::Got->getMipsGotOffset(Body, A); case R_PPC_OPD: { uint64_t SymVA = Body.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -11,6 +11,7 @@ #define LLD_ELF_OUTPUT_SECTIONS_H #include "Config.h" +#include "Relocations.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/SmallPtrSet.h" @@ -113,11 +114,12 @@ void finalize() override; void writeTo(uint8_t *Buf) override; void addEntry(SymbolBody &Sym); + void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr); bool addDynTlsEntry(SymbolBody &Sym); bool addTlsIndex(); - bool empty() const { return MipsLocalEntries == 0 && Entries.empty(); } - uintX_t getMipsLocalEntryOffset(uintX_t EntryValue); + bool empty() const { return MipsPageEntries == 0 && Entries.empty(); } uintX_t getMipsLocalPageOffset(uintX_t Addr); + uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const; uintX_t getGlobalDynAddr(const SymbolBody &B) const; uintX_t getGlobalDynOffset(const SymbolBody &B) const; uintX_t getNumEntries() const { return Entries.size(); } @@ -142,10 +144,26 @@ private: std::vector Entries; uint32_t TlsIndexOff = -1; - uint32_t MipsLocalEntries = 0; + uint32_t MipsPageEntries = 0; // Output sections referenced by MIPS GOT relocations. llvm::SmallPtrSet *, 10> MipsOutSections; llvm::DenseMap MipsLocalGotPos; + + // MIPS ABI requires to create unique GOT entry for each Symbol/Addend + // pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal` + // or `MipsGlobal` vectors. In general it does not have a sence to take in + // account addend for preemptible symbols because the corresponding + // GOT entries should have one-to-one mapping with dynamic symbols table. + // But we use the same container's types for both kind of GOT entries + // to handle them uniformly. + typedef std::pair MipsGotEntry; + typedef std::vector MipsGotEntries; + llvm::DenseMap MipsGotMap; + MipsGotEntries MipsLocal; + MipsGotEntries MipsGlobal; + + // Write MIPS-specific parts of the GOT. + void writeMipsGot(uint8_t *&Buf); }; template Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -92,58 +92,67 @@ this->Header.sh_addralign = sizeof(uintX_t); } -template void GotSection::addEntry(SymbolBody &Sym) { - if (Config->EMachine == EM_MIPS) { - // For "true" local symbols which can be referenced from the same module - // only compiler creates two instructions for address loading: - // - // lw $8, 0($gp) # R_MIPS_GOT16 - // addi $8, $8, 0 # R_MIPS_LO16 - // - // The first instruction loads high 16 bits of the symbol address while - // the second adds an offset. That allows to reduce number of required - // GOT entries because only one global offset table entry is necessary - // for every 64 KBytes of local data. So for local symbols we need to - // allocate number of GOT entries to hold all required "page" addresses. - // - // All global symbols (hidden and regular) considered by compiler uniformly. - // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation - // to load address of the symbol. So for each such symbol we need to - // allocate dedicated GOT entry to store its address. - // - // If a symbol is preemptible we need help of dynamic linker to get its - // final address. The corresponding GOT entries are allocated in the - // "global" part of GOT. Entries for non preemptible global symbol allocated - // in the "local" part of GOT. - // - // See "Global Offset Table" in Chapter 5: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (Sym.isLocal()) { - // At this point we do not know final symbol value so to reduce number - // of allocated GOT entries do the following trick. Save all output - // sections referenced by GOT relocations. Then later in the `finalize` - // method calculate number of "pages" required to cover all saved output - // section and allocate appropriate number of GOT entries. - auto *OutSec = cast>(&Sym)->Section->OutSec; - MipsOutSections.insert(OutSec); - return; - } - if (!Sym.isPreemptible()) { - // In case of non-local symbols require an entry in the local part - // of MIPS GOT, we set GotIndex to 1 just to accent that this symbol - // has the GOT entry and escape creation more redundant GOT entries. - // FIXME (simon): We can try to store such symbols in the `Entries` - // container. But in that case we have to sort out that container - // and update GotIndex assigned to symbols. - Sym.GotIndex = 1; - ++MipsLocalEntries; - return; - } - } +template +void GotSection::addEntry(SymbolBody &Sym) { Sym.GotIndex = Entries.size(); Entries.push_back(&Sym); } +template +void GotSection::addMipsEntry(SymbolBody &Sym, uintX_t Addend, + RelExpr Expr) { + // For "true" local symbols which can be referenced from the same module + // only compiler creates two instructions for address loading: + // + // lw $8, 0($gp) # R_MIPS_GOT16 + // addi $8, $8, 0 # R_MIPS_LO16 + // + // The first instruction loads high 16 bits of the symbol address while + // the second adds an offset. That allows to reduce number of required + // GOT entries because only one global offset table entry is necessary + // for every 64 KBytes of local data. So for local symbols we need to + // allocate number of GOT entries to hold all required "page" addresses. + // + // All global symbols (hidden and regular) considered by compiler uniformly. + // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation + // to load address of the symbol. So for each such symbol we need to + // allocate dedicated GOT entry to store its address. + // + // If a symbol is preemptible we need help of dynamic linker to get its + // final address. The corresponding GOT entries are allocated in the + // "global" part of GOT. Entries for non preemptible global symbol allocated + // in the "local" part of GOT. + // + // See "Global Offset Table" in Chapter 5: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (Expr == R_MIPS_GOT_LOCAL_PAGE) { + // At this point we do not know final symbol value so to reduce number + // of allocated GOT entries do the following trick. Save all output + // sections referenced by GOT relocations. Then later in the `finalize` + // method calculate number of "pages" required to cover all saved output + // section and allocate appropriate number of GOT entries. + auto *OutSec = cast>(&Sym)->Section->OutSec; + MipsOutSections.insert(OutSec); + return; + } + auto AddEntry = [&](SymbolBody &S, uintX_t A, MipsGotEntries &Items) { + if (S.isInGot() && !A) + return; + size_t NewIndex = Items.size(); + if (!MipsGotMap.insert({{&S, A}, NewIndex}).second) + return; + Items.emplace_back(&S, A); + if (!A) + S.GotIndex = NewIndex; + }; + if (Sym.isPreemptible()) { + // Ignore addends for preemptible symbols. They got single GOT entry anyway. + AddEntry(Sym, 0, MipsGlobal); + Sym.IsInGlobalMipsGot = true; + } else + AddEntry(Sym, Addend, MipsLocal); +} + template bool GotSection::addDynTlsEntry(SymbolBody &Sym) { if (Sym.GlobalDynIndex != -1U) return false; @@ -170,22 +179,33 @@ GotSection::getMipsLocalPageOffset(uintX_t EntryValue) { // Initialize the entry by the %hi(EntryValue) expression // but without right-shifting. - return getMipsLocalEntryOffset((EntryValue + 0x8000) & ~0xffff); -} - -template -typename GotSection::uintX_t -GotSection::getMipsLocalEntryOffset(uintX_t EntryValue) { + EntryValue = (EntryValue + 0x8000) & ~0xffff; // Take into account MIPS GOT header. // See comment in the GotSection::writeTo. size_t NewIndex = MipsLocalGotPos.size() + 2; auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex)); - assert(!P.second || MipsLocalGotPos.size() <= MipsLocalEntries); + assert(!P.second || MipsLocalGotPos.size() <= MipsPageEntries); return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset; } template typename GotSection::uintX_t +GotSection::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const { + uintX_t Off = MipsPageEntries; + if (B.IsInGlobalMipsGot) + Off += MipsLocal.size() + B.GotIndex; + else if (B.isInGot()) + Off += B.GotIndex; + else { + auto It = MipsGotMap.find({&B, Addend}); + assert(It != MipsGotMap.end()); + Off += It->second; + } + return Off * sizeof(uintX_t) - MipsGPOffset; +} + +template +typename GotSection::uintX_t GotSection::getGlobalDynAddr(const SymbolBody &B) const { return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t); } @@ -198,12 +218,12 @@ template const SymbolBody *GotSection::getMipsFirstGlobalEntry() const { - return Entries.empty() ? nullptr : Entries.front(); + return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first; } template unsigned GotSection::getMipsLocalEntriesNum() const { - return MipsLocalEntries; + return MipsPageEntries + MipsLocal.size(); } template void GotSection::finalize() { @@ -211,55 +231,62 @@ if (Config->EMachine == EM_MIPS) { // Take into account MIPS GOT header. // See comment in the GotSection::writeTo. - MipsLocalEntries += 2; + MipsPageEntries += 2; for (const OutputSectionBase *OutSec : MipsOutSections) { // Calculate an upper bound of MIPS GOT entries required to store page // addresses of local symbols. We assume the worst case - each 64kb // page of the output section has at least one GOT relocation against it. // Add 0x8000 to the section's size because the page address stored // in the GOT entry is calculated as (value + 0x8000) & ~0xffff. - MipsLocalEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff; + MipsPageEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff; } - EntriesNum += MipsLocalEntries; + EntriesNum += MipsPageEntries + MipsLocal.size() + MipsGlobal.size(); } this->Header.sh_size = EntriesNum * sizeof(uintX_t); } -template void GotSection::writeTo(uint8_t *Buf) { - if (Config->EMachine == EM_MIPS) { - // Set the MSB of the second GOT slot. This is not required by any - // MIPS ABI documentation, though. - // - // There is a comment in glibc saying that "The MSB of got[1] of a - // gnu object is set to identify gnu objects," and in GNU gold it - // says "the second entry will be used by some runtime loaders". - // But how this field is being used is unclear. - // - // We are not really willing to mimic other linkers behaviors - // without understanding why they do that, but because all files - // generated by GNU tools have this special GOT value, and because - // we've been doing this for years, it is probably a safe bet to - // keep doing this for now. We really need to revisit this to see - // if we had to do this. - auto *P = reinterpret_cast(Buf); - P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31); - for (std::pair &L : MipsLocalGotPos) { - uint8_t *Entry = Buf + L.second * sizeof(uintX_t); - write(Entry, L.first); - } - Buf += MipsLocalEntries * sizeof(uintX_t); +template void GotSection::writeMipsGot(uint8_t *&Buf) { + // Set the MSB of the second GOT slot. This is not required by any + // MIPS ABI documentation, though. + // + // There is a comment in glibc saying that "The MSB of got[1] of a + // gnu object is set to identify gnu objects," and in GNU gold it + // says "the second entry will be used by some runtime loaders". + // But how this field is being used is unclear. + // + // We are not really willing to mimic other linkers behaviors + // without understanding why they do that, but because all files + // generated by GNU tools have this special GOT value, and because + // we've been doing this for years, it is probably a safe bet to + // keep doing this for now. We really need to revisit this to see + // if we had to do this. + auto *P = reinterpret_cast(Buf); + P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31); + // Write 'page address' entries to the local part of the GOT. + for (std::pair &L : MipsLocalGotPos) { + uint8_t *Entry = Buf + L.second * sizeof(uintX_t); + write(Entry, L.first); } + Buf += MipsPageEntries * sizeof(uintX_t); + auto AddEntry = [&](const MipsGotEntry &SA) { + uint8_t *Entry = Buf; + Buf += sizeof(uintX_t); + uintX_t VA = SA.first->template getVA(SA.second); + write(Entry, VA); + }; + std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry); + std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry); +} + +template void GotSection::writeTo(uint8_t *Buf) { + if (Config->EMachine == EM_MIPS) + writeMipsGot(Buf); for (const SymbolBody *B : Entries) { uint8_t *Entry = Buf; Buf += sizeof(uintX_t); if (!B) continue; - // MIPS has special rules to fill up GOT entries. - // 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 - // As the first approach, we can just store addresses for all symbols. - if (Config->EMachine != EM_MIPS && B->isPreemptible()) + if (B->isPreemptible()) continue; // The dynamic linker will take care of it. uintX_t VA = B->getVA(); write(Entry, VA); @@ -1249,10 +1276,8 @@ const std::pair &R) { // Sort entries related to non-local preemptible symbols by GOT indexes. // All other entries go to the first part of GOT in arbitrary order. - bool LIsInLocalGot = !L.first->isInGot() || !L.first->isPreemptible(); - bool RIsInLocalGot = !R.first->isInGot() || !R.first->isPreemptible(); - if (LIsInLocalGot || RIsInLocalGot) - return !RIsInLocalGot; + if (!L.first->IsInGlobalMipsGot || !R.first->IsInGlobalMipsGot) + return !L.first->IsInGlobalMipsGot; return L.first->GotIndex < R.first->GotIndex; } Index: ELF/Relocations.h =================================================================== --- ELF/Relocations.h +++ ELF/Relocations.h @@ -28,8 +28,8 @@ R_GOT_PAGE_PC, R_GOT_PC, R_HINT, - R_MIPS_GOT_LOCAL, R_MIPS_GOT_LOCAL_PAGE, + R_MIPS_GOT_OFF, R_NEG_TLS, R_PAGE_PC, R_PC, Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -59,10 +59,10 @@ namespace elf { static bool refersToGotEntry(RelExpr Expr) { - return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL || - Expr == R_MIPS_GOT_LOCAL_PAGE || Expr == R_GOT_PAGE_PC || - Expr == R_GOT_PC || Expr == R_GOT_FROM_END || Expr == R_TLSGD || - Expr == R_TLSGD_PC || Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE; + return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL_PAGE || + Expr == R_MIPS_GOT_OFF || Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC || + Expr == R_GOT_FROM_END || Expr == R_TLSGD || Expr == R_TLSGD_PC || + Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE; } static bool isPreemptible(const SymbolBody &Body, uint32_t Type) { @@ -271,9 +271,9 @@ const SymbolBody &Body) { // These expressions always compute a constant if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF || - E == R_MIPS_GOT_LOCAL || E == R_MIPS_GOT_LOCAL_PAGE || - E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC || - E == R_TLSGD || E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE || E == R_HINT) + E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF || E == R_GOT_PAGE_PC || + E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC || E == R_TLSGD || + E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE || E == R_HINT) return true; // These never do, except if the entire file is position dependent or if @@ -466,8 +466,6 @@ // For details see p. 4-19 at // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf Addend += 4; - if (Expr == R_GOT_OFF) - Addend -= MipsGPOffset; if (Expr == R_GOTREL) { Addend -= MipsGPOffset; if (Body.isLocal()) @@ -574,8 +572,8 @@ // to the GOT entry and reads the GOT entry when it needs to perform // a dynamic relocation. // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 - if (Config->EMachine == EM_MIPS && !Body.isInGot()) - Out::Got->addEntry(Body); + if (Config->EMachine == EM_MIPS) + Out::Got->addMipsEntry(Body, Addend, Expr); continue; } @@ -605,18 +603,20 @@ } if (refersToGotEntry(Expr)) { - if (Body.isInGot()) - continue; - Out::Got->addEntry(Body); - - if (Config->EMachine == EM_MIPS) + if (Config->EMachine == EM_MIPS) { // MIPS ABI has special rules to process GOT entries // and doesn't require relocation entries for them. // 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 + Out::Got->addMipsEntry(Body, Addend, Expr); + continue; + } + + if (Body.isInGot()) continue; + Out::Got->addEntry(Body); if (Preemptible || (Config->Pic && !isAbsolute(Body))) { uint32_t DynType; if (Body.isTls()) Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -127,6 +127,9 @@ // True if this is a local symbol. unsigned IsLocal : 1; + // True if this symbol has an entry in the global part of MIPS GOT. + unsigned IsInGlobalMipsGot : 1; + // The following fields have the same meaning as the ELF symbol attributes. uint8_t Type; // symbol type uint8_t StOther; // st_other field value Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -92,12 +92,14 @@ SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type) - : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true), Type(Type), - StOther(StOther), NameOffset(NameOffset) {} + : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true), + IsInGlobalMipsGot(false), Type(Type), StOther(StOther), + NameOffset(NameOffset) {} SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type) - : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false), Type(Type), - StOther(StOther), Name({Name.data(), Name.size()}) {} + : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false), + IsInGlobalMipsGot(false), Type(Type), StOther(StOther), + Name({Name.data(), Name.size()}) {} // Returns true if a symbol can be replaced at load-time by a symbol // with the same name defined in other ELF executable or DSO. @@ -149,8 +151,7 @@ } template typename ELFT::uint SymbolBody::getGotOffset() const { - return (Out::Got->getMipsLocalEntriesNum() + GotIndex) * - sizeof(typename ELFT::uint); + return GotIndex * sizeof(typename ELFT::uint); } template typename ELFT::uint SymbolBody::getGotPltVA() const { Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -1764,9 +1764,7 @@ // fallthrough case R_MIPS_CALL16: case R_MIPS_GOT_DISP: - if (!S.isPreemptible()) - return R_MIPS_GOT_LOCAL; - return R_GOT_OFF; + return R_MIPS_GOT_OFF; case R_MIPS_GOT_PAGE: return R_MIPS_GOT_LOCAL_PAGE; } Index: test/ELF/mips-64-disp.s =================================================================== --- /dev/null +++ test/ELF/mips-64-disp.s @@ -0,0 +1,89 @@ +# Check R_MIPS_GOT_DISP relocations against various kind of symbols. + +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ +# RUN: %p/Inputs/mips-pic.s -o %t.so.o +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.exe.o +# RUN: ld.lld %t.so.o -shared -o %t.so +# RUN: ld.lld %t.exe.o %t.so -o %t.exe +# RUN: llvm-objdump -d -t %t.exe | FileCheck %s +# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s + +# REQUIRES: mips + +# CHECK: __start: +# CHECK-NEXT: 20000: 24 42 80 40 addiu $2, $2, -32704 +# CHECK-NEXT: 20004: 24 42 80 20 addiu $2, $2, -32736 +# CHECK-NEXT: 20008: 24 42 80 28 addiu $2, $2, -32728 +# CHECK-NEXT: 2000c: 24 42 80 30 addiu $2, $2, -32720 +# CHECK-NEXT: 20010: 24 42 80 38 addiu $2, $2, -32712 + +# CHECK: 0000000000020014 .text 00000000 foo +# CHECK: 0000000000037ff0 .got 00000000 .hidden _gp +# CHECK: 0000000000020000 .text 00000000 __start +# CHECK: 0000000000000000 g F *UND* 00000000 foo1a + +# GOT: Relocations [ +# GOT-NEXT: ] +# GOT-NEXT: Primary GOT { +# GOT-NEXT: Canonical gp value: 0x37FF0 +# GOT-NEXT: Reserved entries [ +# GOT-NEXT: Entry { +# GOT-NEXT: Address: 0x30000 +# GOT-NEXT: Access: -32752 +# GOT-NEXT: Initial: 0x0 +# GOT-NEXT: Purpose: Lazy resolver +# GOT-NEXT: } +# GOT-NEXT: Entry { +# GOT-NEXT: Address: 0x30008 +# GOT-NEXT: Access: -32744 +# GOT-NEXT: Initial: 0x8000000000000000 +# GOT-NEXT: Purpose: Module pointer (GNU extension) +# GOT-NEXT: } +# GOT-NEXT: ] +# GOT-NEXT: Local entries [ +# GOT-NEXT: Entry { +# GOT-NEXT: Address: 0x30010 +# GOT-NEXT: Access: -32736 +# GOT-NEXT: Initial: 0x20014 +# GOT-NEXT: } +# GOT-NEXT: Entry { +# GOT-NEXT: Address: 0x30018 +# GOT-NEXT: Access: -32728 +# GOT-NEXT: Initial: 0x20004 +# GOT-NEXT: } +# GOT-NEXT: Entry { +# GOT-NEXT: Address: 0x30020 +# GOT-NEXT: Access: -32720 +# GOT-NEXT: Initial: 0x20008 +# GOT-NEXT: } +# GOT-NEXT: Entry { +# GOT-NEXT: Address: 0x30028 +# GOT-NEXT: Access: -32712 +# GOT-NEXT: Initial: 0x2000C +# GOT-NEXT: } +# GOT-NEXT: ] +# GOT-NEXT: Global entries [ +# GOT-NEXT: Entry { +# GOT-NEXT: Address: 0x30030 +# GOT-NEXT: Access: -32704 +# GOT-NEXT: Initial: 0x0 +# GOT-NEXT: Value: 0x0 +# GOT-NEXT: Type: Function +# GOT-NEXT: Section: Undefined +# GOT-NEXT: Name: foo1a +# GOT-NEXT: } +# GOT-NEXT: ] +# GOT-NEXT: Number of TLS and multi-GOT entries: 0 +# GOT-NEXT: } + + .text + .global __start +__start: + addiu $v0,$v0,%got_disp(foo1a) # R_MIPS_GOT_DISP + addiu $v0,$v0,%got_disp(foo) # R_MIPS_GOT_DISP + addiu $v0,$v0,%got_disp(.text+4) # R_MIPS_GOT_DISP + addiu $v0,$v0,%got_disp(.text+8) # R_MIPS_GOT_DISP + addiu $v0,$v0,%got_disp(.text+12) # R_MIPS_GOT_DISP + +foo: + nop Index: test/ELF/mips-64-got.s =================================================================== --- test/ELF/mips-64-got.s +++ test/ELF/mips-64-got.s @@ -13,14 +13,15 @@ # CHECK: __start: # CHECK-NEXT: 20000: df 82 80 20 ld $2, -32736($gp) -# CHECK-NEXT: 20004: 64 42 00 14 daddiu $2, $2, 20 -# CHECK-NEXT: 20008: 24 42 80 30 addiu $2, $2, -32720 +# CHECK-NEXT: 20004: 64 42 00 18 daddiu $2, $2, 24 +# CHECK-NEXT: 20008: 24 42 80 38 addiu $2, $2, -32712 # CHECK-NEXT: 2000c: 24 42 80 28 addiu $2, $2, -32728 +# CHECK-NEXT: 20010: 24 42 80 30 addiu $2, $2, -32720 -# CHECK: 0000000000020014 .text 00000000 foo +# CHECK: 0000000000020018 .text 00000000 foo # CHECK: 0000000000037ff0 .got 00000000 .hidden _gp # CHECK: 0000000000020000 .text 00000000 __start -# CHECK: 0000000000020010 .text 00000000 bar +# CHECK: 0000000000020014 .text 00000000 bar # GOT: Relocations [ # GOT-NEXT: ] @@ -49,13 +50,18 @@ # GOT-NEXT: Entry { # GOT-NEXT: Address: 0x30018 # GOT-NEXT: Access: -32728 -# GOT-NEXT: Initial: 0x20010 +# GOT-NEXT: Initial: 0x20014 # GOT-NEXT: } -# GOT-NEXT: ] -# GOT-NEXT: Global entries [ # GOT-NEXT: Entry { # GOT-NEXT: Address: 0x30020 # GOT-NEXT: Access: -32720 +# GOT-NEXT: Initial: 0x20018 +# GOT-NEXT: } +# GOT-NEXT: ] +# GOT-NEXT: Global entries [ +# GOT-NEXT: Entry { +# GOT-NEXT: Address: 0x30028 +# GOT-NEXT: Access: -32712 # GOT-NEXT: Initial: 0x0 # GOT-NEXT: Value: 0x0 # GOT-NEXT: Type: Function @@ -73,6 +79,7 @@ daddiu $v0,$v0,%got_ofst(foo) # R_MIPS_GOT_OFST addiu $v0,$v0,%got_disp(foo1a) # R_MIPS_GOT_DISP addiu $v0,$v0,%got_disp(bar) # R_MIPS_GOT_DISP + addiu $v0,$v0,%got_disp(foo) # R_MIPS_GOT_DISP bar: nop Index: test/ELF/mips-dynamic.s =================================================================== --- test/ELF/mips-dynamic.s +++ test/ELF/mips-dynamic.s @@ -71,8 +71,8 @@ # DSO: ] # DSO: DynamicSymbols [ # DSO: Name: @ -# DSO: Name: __start@ # DSO: Name: _foo@ +# DSO: Name: __start@ # DSO: ] # DSO: DynamicSection [ # DSO-NEXT: Tag Type Name/Value Index: test/ELF/mips-got16.s =================================================================== --- test/ELF/mips-got16.s +++ test/ELF/mips-got16.s @@ -17,7 +17,7 @@ # CHECK-NEXT: 10014: 21 08 90 04 addi $8, $8, -28668 # CHECK-NEXT: 10018: 8f 88 80 20 lw $8, -32736($gp) # CHECK-NEXT: 1001c: 21 08 10 04 addi $8, $8, 4100 -# CHECK-NEXT: 10020: 8f 88 80 24 lw $8, -32732($gp) +# CHECK-NEXT: 10020: 8f 88 80 28 lw $8, -32728($gp) # CHECK-NEXT: 10024: 21 08 10 08 addi $8, $8, 4104 # CHECK-NEXT: 10028: 8f 88 80 2c lw $8, -32724($gp) # @@ -67,14 +67,14 @@ # GOT-NEXT: Entry { # GOT-NEXT: Address: 0x20014 # GOT-NEXT: Access: -32732 -# GOT-NEXT: Initial: 0x51008 -# ^-- 'bar' address +# GOT-NEXT: Initial: 0x0 +# ^-- redundant unused entry # GOT-NEXT: } # GOT-NEXT: Entry { # GOT-NEXT: Address: 0x20018 -# GOT-NEXT: Access: -32728 -# GOT-NEXT: Initial: 0x0 -# ^-- redundant unused entry +# GOT-NEXT: Access: -327 +# GOT-NEXT: Initial: 0x51008 +# ^-- 'bar' address # GOT-NEXT: } # GOT-NEXT: ] # GOT-NEXT: Global entries [ Index: test/ELF/mips-plt-copy.s =================================================================== --- test/ELF/mips-plt-copy.s +++ test/ELF/mips-plt-copy.s @@ -12,8 +12,8 @@ # CHECK: Relocations [ # CHECK-NEXT: Section ({{.*}}) .rel.dyn { -# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0 # CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_COPY data1 0x0 +# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0 # CHECK-NEXT: } # CHECK-NEXT: Section ({{.*}}) .rel.plt { # CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0 Index: test/ELF/mips-sto-plt.s =================================================================== --- test/ELF/mips-sto-plt.s +++ test/ELF/mips-sto-plt.s @@ -10,23 +10,23 @@ # REQUIRES: mips # CHECK: Symbol { -# CHECK: Name: foo0@ -# CHECK-NEXT: Value: 0x0 +# CHECK: Name: foo1@ +# CHECK-NEXT: Value: 0x20050 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: Function -# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Other [ (0x8) +# CHECK-NEXT: STO_MIPS_PLT +# CHECK-NEXT: ] # CHECK-NEXT: Section: Undefined # CHECK-NEXT: } # CHECK: Symbol { -# CHECK: Name: foo1@ -# CHECK-NEXT: Value: 0x20050 +# CHECK: Name: foo0@ +# CHECK-NEXT: Value: 0x0 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: Function -# CHECK-NEXT: Other [ (0x8) -# CHECK-NEXT: STO_MIPS_PLT -# CHECK-NEXT: ] +# CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: Undefined # CHECK-NEXT: }