Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -191,6 +191,7 @@ uint16_t EMachine = llvm::ELF::EM_NONE; llvm::Optional ImageBase; uint64_t MaxPageSize; + uint64_t MipsGotSize; uint64_t ZStackSize; unsigned LTOPartitions; unsigned LTOO; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -715,6 +715,7 @@ Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1); Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile); Config->MapFile = Args.getLastArgValue(OPT_Map); + Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0); Config->MergeArmExidx = Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true); Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec); Index: ELF/DriverUtils.cpp =================================================================== --- ELF/DriverUtils.cpp +++ ELF/DriverUtils.cpp @@ -28,6 +28,7 @@ #include "llvm/Support/Process.h" using namespace llvm; +using namespace llvm::opt; using namespace llvm::sys; using namespace llvm::opt; Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -120,6 +120,9 @@ static bool IsInGroup; static uint32_t NextGroupId; + // Index of MIPS GOT built for this file. + llvm::Optional MipsGotIndex; + protected: InputFile(Kind K, MemoryBufferRef M); std::vector Sections; Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -462,8 +462,8 @@ return OS->PtLoad->FirstSec->Addr; } -static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P, - const Symbol &Sym, RelExpr Expr) { +static uint64_t getRelocTargetVA(const InputFile &File, RelType Type, int64_t A, + uint64_t P, const Symbol &Sym, RelExpr Expr) { switch (Expr) { case R_INVALID: return 0; @@ -501,9 +501,9 @@ case R_TLSDESC_CALL: llvm_unreachable("cannot relocate hint relocs"); case R_MIPS_GOTREL: - return Sym.getVA(A) - InX::MipsGot->getGp(); + return Sym.getVA(A) - InX::MipsGot->getGp(&File); case R_MIPS_GOT_GP: - return InX::MipsGot->getGp() + A; + return InX::MipsGot->getGp(&File) + A; case R_MIPS_GOT_GP_PC: { // R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target // is _gp_disp symbol. In that case we should use the following @@ -512,7 +512,7 @@ // microMIPS variants of these relocations use slightly different // expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi() // to correctly handle less-sugnificant bit of the microMIPS symbol. - uint64_t V = InX::MipsGot->getGp() + A - P; + uint64_t V = InX::MipsGot->getGp(&File) + A - P; if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16) V += 4; if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16) @@ -523,21 +523,24 @@ // If relocation against MIPS local symbol requires GOT entry, this entry // should be initialized by 'page address'. This address is high 16-bits // of sum the symbol's value and the addend. - return InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Sym, A) - - InX::MipsGot->getGp(); + return InX::MipsGot->getVA() + + InX::MipsGot->getPageEntryOffset(File, Sym, A) - + InX::MipsGot->getGp(&File); case R_MIPS_GOT_OFF: case R_MIPS_GOT_OFF32: // 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 InX::MipsGot->getVA() + InX::MipsGot->getSymEntryOffset(Sym, A) - - InX::MipsGot->getGp(); + return InX::MipsGot->getVA() + + InX::MipsGot->getSymEntryOffset(File, Sym, A) - + InX::MipsGot->getGp(&File); case R_MIPS_TLSGD: - return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() + - InX::MipsGot->getGlobalDynOffset(Sym) - InX::MipsGot->getGp(); + return InX::MipsGot->getVA() + + InX::MipsGot->getGlobalDynOffset(File, Sym) - + InX::MipsGot->getGp(&File); case R_MIPS_TLSLD: - return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() + - InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp(); + return InX::MipsGot->getVA() + InX::MipsGot->getTlsIndexOffset(File) - + InX::MipsGot->getGp(&File); case R_PAGE_PC: case R_PLT_PAGE_PC: { uint64_t Dest; @@ -717,7 +720,8 @@ uint64_t AddrLoc = getOutputSection()->Addr + Offset; RelExpr Expr = Rel.Expr; uint64_t TargetVA = SignExtend64( - getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits); + getRelocTargetVA(*File, Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), + Bits); switch (Expr) { case R_RELAX_GOT_PC: Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -457,3 +457,7 @@ def EL : F<"EL">; def G: JoinedOrSeparate<["-"], "G">; def Qy : F<"Qy">; + +// Hidden option used for testing MIPS multi-GOT implementation. +defm mips_got_size: Eq<"mips-got-size">, Flags<[HelpHidden]>, + HelpText<"Max size of a single MIPS GOT. 0x10000 by default.">; Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -85,27 +85,16 @@ // pollute other `handleTlsRelocation` by MIPS `ifs` statements. // Mips has a custom MipsGotSection that handles the writing of GOT entries // without dynamic relocations. -template static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, uint64_t Offset, int64_t Addend, RelExpr Expr) { if (Expr == R_MIPS_TLSLD) { - if (InX::MipsGot->addTlsIndex() && Config->Pic) - InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::MipsGot, - InX::MipsGot->getTlsIndexOff(), nullptr); + InX::MipsGot->addTlsIndex(*C.File); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } - if (Expr == R_MIPS_TLSGD) { - if (InX::MipsGot->addDynTlsEntry(Sym) && Sym.IsPreemptible) { - uint64_t Off = InX::MipsGot->getGlobalDynOffset(Sym); - InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::MipsGot, Off, - &Sym); - if (Sym.IsPreemptible) - InX::RelaDyn->addReloc(Target->TlsOffsetRel, InX::MipsGot, - Off + Config->Wordsize, &Sym); - } + InX::MipsGot->addDynTlsEntry(*C.File, Sym); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } @@ -184,7 +173,7 @@ if (Config->EMachine == EM_ARM) return handleARMTlsRelocation(Type, Sym, C, Offset, Addend, Expr); if (Config->EMachine == EM_MIPS) - return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr); + return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr); if (isRelExprOneOf(Expr) && Config->Shared) { @@ -474,7 +463,6 @@ Sym.PltIndex = Old.PltIndex; Sym.GotIndex = Old.GotIndex; Sym.VerdefIndex = Old.VerdefIndex; - Sym.IsInGlobalMipsGot = Old.IsInGlobalMipsGot; Sym.IsPreemptible = true; Sym.ExportDynamic = true; Sym.IsUsedInRegularObj = true; @@ -814,7 +802,7 @@ // a dynamic relocation. // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 if (Config->EMachine == EM_MIPS) - InX::MipsGot->addEntry(Sym, Addend, Expr); + InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); return; } } @@ -1000,10 +988,7 @@ // 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 - InX::MipsGot->addEntry(Sym, Addend, Expr); - if (Sym.isTls() && Sym.IsPreemptible) - InX::RelaDyn->addReloc(Target->TlsGotRel, InX::MipsGot, - Sym.getGotOffset(), &Sym); + InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); } else if (!Sym.isInGot()) { addGotEntry(Sym); } Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -158,19 +158,13 @@ uint8_t StOther, uint8_t Type) : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding), Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false), - IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), - IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections), - NeedsTocRestore(false) {} + IsInIplt(false), IsInIgot(false), IsPreemptible(false), + Used(!Config->GcSections), NeedsTocRestore(false) {} public: // True the symbol should point to its PLT entry. // For SharedSymbol only. unsigned NeedsPltAddr : 1; - // True if this symbol has an entry in the global part of MIPS GOT. - unsigned IsInGlobalMipsGot : 1; - - // True if this symbol is referenced by 32-bit GOT relocations. - unsigned Is32BitMipsGot : 1; // True if this symbol is in the Iplt sub-section of the Plt. unsigned IsInIplt : 1; Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -178,12 +178,21 @@ bool updateAllocSize() override; void finalizeContents() override; bool empty() const override; - void addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr); - bool addDynTlsEntry(Symbol &Sym); - bool addTlsIndex(); - uint64_t getPageEntryOffset(const Symbol &B, int64_t Addend) const; - uint64_t getSymEntryOffset(const Symbol &B, int64_t Addend) const; - uint64_t getGlobalDynOffset(const Symbol &B) const; + + // Join separate GOTs built for each input file to generate + // primary and optional multiple secondary GOTs. + template void build(); + + void addEntry(InputFile &File, Symbol &Sym, int64_t Addend, RelExpr Expr); + void addDynTlsEntry(InputFile &File, Symbol &Sym); + void addTlsIndex(InputFile &File); + + uint64_t getPageEntryOffset(const InputFile &F, const Symbol &S, + int64_t Addend) const; + uint64_t getSymEntryOffset(const InputFile &F, const Symbol &S, + int64_t Addend) const; + uint64_t getGlobalDynOffset(const InputFile &F, const Symbol &S) const; + uint64_t getTlsIndexOffset(const InputFile &F) const; // Returns the symbol which corresponds to the first entry of the global part // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic @@ -195,13 +204,8 @@ // the number of reserved entries. unsigned getLocalEntriesNum() const; - // Returns offset of TLS part of the MIPS GOT table. This part goes - // after 'local' and 'global' entries. - uint64_t getTlsOffset() const; - - uint32_t getTlsIndexOff() const { return TlsIndexOff; } - - uint64_t getGp() const; + // Return _gp value for primary GOT (nullptr) or particular input file. + uint64_t getGp(const InputFile *F = nullptr) const; private: // MIPS GOT consists of three parts: local, global and tls. Each part @@ -240,32 +244,110 @@ // addressing, but MIPS ABI requires that these entries be present in GOT. // TLS entries: // Entries created by TLS relocations. + // + // If the sum of local, global and tls entries is less than 64K only single + // got is enough. Otherwise, multi-got is created. Series of primary and + // multiple secondary GOTs have the following layout: + // - Primary GOT + // Header + // Local entries + // Global entries + // Relocation only entries + // TLS entries + // + // - Secondary GOT + // Local entries + // Global entries + // TLS entries + // ... + // + // All GOT entries required by relocations from a single input file entirely + // belong to either primary or one of secondary GOTs. To reference GOT entries + // each GOT has its own _gp value points to the "middle" of the GOT. + // In the code this value loaded to the register which is used for GOT access. + // + // MIPS 32 function's prologue: + // lui v0,0x0 + // 0: R_MIPS_HI16 _gp_disp + // addiu v0,v0,0 + // 4: R_MIPS_LO16 _gp_disp + // + // MIPS 64: + // lui at,0x0 + // 14: R_MIPS_GPREL16 main + // + // Dynamic linker does not know anything about secondary GOTs and cannot + // use a regular MIPS mechanism for GOT entries initialization. So we have + // to use an approach accepted by other architectures and create dynamic + // relocations R_MIPS_REL32 to initialize global entries (and local in case + // of PIC code) in secondary GOTs. But ironically MIPS dynamic linker + // requires GOT entries and correspondingly ordered dynamic symbol table + // entries to deal with dynamic relocations. To handle this problem + // relocation-only section in the primary GOT contains entries for all + // symbols referenced in global parts of secondary GOTs. Although the sum + // of local and normal global entries of the primary got should be less + // than 64K, the size of the primary got (including relocation-only entries + // can be greater than 64K, because parts of the primary got that overflow + // the 64K limit are used only by the dynamic linker at dynamic link-time + // and not by 16-bit gp-relative addressing at run-time. + // + // For complete multi-GOT description see the following link + // https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT // Number of "Header" entries. static const unsigned HeaderEntriesNum = 2; - // Number of allocated "Page" entries. - uint32_t PageEntriesNum = 0; - // Map output sections referenced by MIPS GOT relocations - // to the first index of "Page" entries allocated for this section. - llvm::SmallMapVector PageIndexMap; - - typedef std::pair GotEntry; - typedef std::vector GotEntries; - // Map from Symbol-Addend pair to the GOT index. - llvm::DenseMap EntryIndexMap; - // Local entries (16-bit access). - GotEntries LocalEntries; - // Local entries (32-bit access). - GotEntries LocalEntries32; - - // Normal and reloc-only global entries. - GotEntries GlobalEntries; - - // TLS entries. - std::vector TlsEntries; - uint32_t TlsIndexOff = -1; uint64_t Size = 0; + + size_t LocalEntriesNum = 0; + + // Symbol and addend. + typedef std::pair GotEntry; + + struct FileGot { + InputFile *File = nullptr; + size_t StartIndex = 0; + + struct PageBlock { + size_t FirstIndex = 0; + size_t Count = 0; + }; + + // Map output sections referenced by MIPS GOT relocations + // to the description (index/count) "page" entries allocated + // for this section. + llvm::SmallMapVector PagesMap; + // Maps from Symbol+Addend pair or just Symbol to the GOT entry index. + llvm::MapVector Local16; + llvm::MapVector Local32; + llvm::MapVector Global; + llvm::MapVector Relocs; + llvm::MapVector Tls; + // Set of symbols referenced by dynamic TLS relocations. + llvm::MapVector DynTlsSymbols; + + // Total number of all entries. + size_t getEntriesNum() const; + // Number of "page" entries. + size_t getPageEntriesNum() const; + // Number of entries require 16-bit index to access. + size_t getIndexedEntriesNum() const; + + bool isOverflow() const; + }; + + // Container of GOT created for each input file. + // After building a final series of GOTs this container + // holds primary and secondary GOT's. + std::vector Gots; + + // Return (and create if necessary) `FileGot`. + FileGot &getGot(InputFile &F); + + // Try to merge two GOTs. In case of success the `Dst` contains + // result of merging and the function returns true. In case of + // ovwerflow the `Dst` is unchanged and the function returns false. + bool tryMergeGots(FileGot & Dst, FileGot & Src, bool IsPrimary); }; class GotPltSection final : public SyntheticSection { @@ -318,7 +400,15 @@ DynamicReloc(RelType Type, const InputSectionBase *InputSec, uint64_t OffsetInSec, bool UseSymVA, Symbol *Sym, int64_t Addend) : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec), - UseSymVA(UseSymVA), Addend(Addend) {} + UseSymVA(UseSymVA), Addend(Addend), OutputSec(nullptr) {} + // This constructor records dynamic relocation settings used by MIPS + // multi-GOT implementation. It's to relocate addresses of 64kb pages + // lie inside the output section. + DynamicReloc(RelType Type, const InputSectionBase *InputSec, + uint64_t OffsetInSec, const OutputSection *OutputSec, + int64_t Addend) + : Type(Type), Sym(nullptr), InputSec(InputSec), OffsetInSec(OffsetInSec), + UseSymVA(false), Addend(Addend), OutputSec(OutputSec) {} uint64_t getOffset() const; uint32_t getSymIndex() const; @@ -341,6 +431,7 @@ // plus the original addend as the final relocation addend. bool UseSymVA; int64_t Addend; + const OutputSection *OutputSec; }; template class DynamicSection final : public SyntheticSection { Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -29,6 +29,7 @@ #include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" +#include "llvm/ADT/SetOperations.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/Decompressor.h" @@ -644,92 +645,34 @@ : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, ".got") {} -void MipsGotSection::addEntry(Symbol &Sym, int64_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. - PageIndexMap.insert({Sym.getOutputSection(), 0}); - return; - } - if (Sym.isTls()) { - // GOT entries created for MIPS TLS relocations behave like - // almost GOT entries from other ABIs. They go to the end - // of the global offset table. - Sym.GotIndex = TlsEntries.size(); - TlsEntries.push_back(&Sym); - return; - } - auto AddEntry = [&](Symbol &S, uint64_t A, GotEntries &Items) { - if (S.isInGot() && !A) - return; - size_t NewIndex = Items.size(); - if (!EntryIndexMap.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, GlobalEntries); - Sym.IsInGlobalMipsGot = true; - } else if (Expr == R_MIPS_GOT_OFF32) { - AddEntry(Sym, Addend, LocalEntries32); - Sym.Is32BitMipsGot = true; - } else { - // Hold local GOT entries accessed via a 16-bit index separately. - // That allows to write them in the beginning of the GOT and keep - // their indexes as less as possible to escape relocation's overflow. - AddEntry(Sym, Addend, LocalEntries); - } +void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend, + RelExpr Expr) { + FileGot &G = getGot(File); + if (Expr == R_MIPS_GOT_LOCAL_PAGE) + G.PagesMap.insert({Sym.getOutputSection(), {}}); + else if (Sym.isTls()) + G.Tls.insert({&Sym, 0}); + else if (Sym.IsPreemptible && Expr == R_ABS) + G.Relocs.insert({&Sym, 0}); + else if (Sym.IsPreemptible) + G.Global.insert({&Sym, 0}); + else if (Expr == R_MIPS_GOT_OFF32) + G.Local32.insert({{&Sym, Addend}, 0}); + else + G.Local16.insert({{&Sym, Addend}, 0}); } -bool MipsGotSection::addDynTlsEntry(Symbol &Sym) { - if (Sym.GlobalDynIndex != -1U) - return false; - Sym.GlobalDynIndex = TlsEntries.size(); - // Global Dynamic TLS entries take two GOT slots. - TlsEntries.push_back(nullptr); - TlsEntries.push_back(&Sym); - return true; +void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) { + getGot(File).DynTlsSymbols.insert({&Sym, 0}); } -// Reserves TLS entries for a TLS module ID and a TLS block offset. -// In total it takes two GOT slots. -bool MipsGotSection::addTlsIndex() { - if (TlsIndexOff != uint32_t(-1)) - return false; - TlsIndexOff = TlsEntries.size() * Config->Wordsize; - TlsEntries.push_back(nullptr); - TlsEntries.push_back(nullptr); - return true; +void MipsGotSection::addTlsIndex(InputFile &File) { + getGot(File).DynTlsSymbols.insert({nullptr, 0}); +} + +size_t MipsGotSection::FileGot::getEntriesNum() const { + return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() + + Tls.size() + DynTlsSymbols.size() * 2; } static uint64_t getMipsPageAddr(uint64_t Addr) { @@ -740,80 +683,296 @@ return (Size + 0xfffe) / 0xffff + 1; } -uint64_t MipsGotSection::getPageEntryOffset(const Symbol &B, +size_t MipsGotSection::FileGot::getPageEntriesNum() const { + size_t Num = 0; + for (const std::pair &P : PagesMap) + Num += P.second.Count; + return Num; +} + +size_t MipsGotSection::FileGot::getIndexedEntriesNum() const { + size_t Count = getPageEntriesNum() + Local16.size() + Global.size(); + // If there are relocation-only entries in the GOT, TLS entries + // are allocated after them. TLS entries should be addressable + // by 16-bit index so count both reloc-only and TLS entries. + if (!Tls.empty() || !DynTlsSymbols.empty()) + Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2; + return Count; +} + +MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) { + if (!F.MipsGotIndex.hasValue()) { + Gots.emplace_back(); + Gots.back().File = &F; + F.MipsGotIndex = Gots.size() - 1; + } + return Gots[*F.MipsGotIndex]; +} + +uint64_t MipsGotSection::getPageEntryOffset(const InputFile &F, + const Symbol &Sym, int64_t Addend) const { - const OutputSection *OutSec = B.getOutputSection(); + const FileGot &G = Gots[*F.MipsGotIndex]; + const OutputSection *OutSec = Sym.getOutputSection(); uint64_t SecAddr = getMipsPageAddr(OutSec->Addr); - uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend)); - uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff; - assert(Index < PageEntriesNum); - return (HeaderEntriesNum + Index) * Config->Wordsize; + uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend)); + uint64_t Index = + G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff; + return Index * Config->Wordsize; } -uint64_t MipsGotSection::getSymEntryOffset(const Symbol &B, +uint64_t MipsGotSection::getSymEntryOffset(const InputFile &F, const Symbol &S, int64_t Addend) const { - // Calculate offset of the GOT entries block: TLS, global, local. - uint64_t Index = HeaderEntriesNum + PageEntriesNum; - if (B.isTls()) - Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size(); - else if (B.IsInGlobalMipsGot) - Index += LocalEntries.size() + LocalEntries32.size(); - else if (B.Is32BitMipsGot) - Index += LocalEntries.size(); - // Calculate offset of the GOT entry in the block. - if (B.isInGot()) - Index += B.GotIndex; - else { - auto It = EntryIndexMap.find({&B, Addend}); - assert(It != EntryIndexMap.end()); - Index += It->second; - } - return Index * Config->Wordsize; + const FileGot &G = Gots[*F.MipsGotIndex]; + Symbol *Sym = const_cast(&S); + if (Sym->isTls()) + return G.Tls.find(Sym)->second * Config->Wordsize; + if (Sym->IsPreemptible) + return G.Global.find(Sym)->second * Config->Wordsize; + return G.Local16.find({Sym, Addend})->second * Config->Wordsize; } -uint64_t MipsGotSection::getTlsOffset() const { - return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize; +uint64_t MipsGotSection::getTlsIndexOffset(const InputFile &F) const { + const FileGot &G = Gots[*F.MipsGotIndex]; + return G.DynTlsSymbols.find(nullptr)->second * Config->Wordsize; } -uint64_t MipsGotSection::getGlobalDynOffset(const Symbol &B) const { - return B.GlobalDynIndex * Config->Wordsize; +uint64_t MipsGotSection::getGlobalDynOffset(const InputFile &F, + const Symbol &S) const { + const FileGot &G = Gots[*F.MipsGotIndex]; + Symbol *Sym = const_cast(&S); + return G.DynTlsSymbols.find(Sym)->second * Config->Wordsize; } const Symbol *MipsGotSection::getFirstGlobalEntry() const { - return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first; + if (!Gots.empty()) { + const FileGot &PrimGot = Gots.front(); + if (!PrimGot.Global.empty()) + return PrimGot.Global.front().first; + if (!PrimGot.Relocs.empty()) + return PrimGot.Relocs.front().first; + } + return nullptr; } unsigned MipsGotSection::getLocalEntriesNum() const { - return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() + - LocalEntries32.size(); + if (Gots.empty()) + return HeaderEntriesNum; + return HeaderEntriesNum + Gots.front().getPageEntriesNum() + + Gots.front().Local16.size(); +} + +bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) { + FileGot Tmp = Dst; + set_union(Tmp.PagesMap, Src.PagesMap); + set_union(Tmp.Local16, Src.Local16); + set_union(Tmp.Global, Src.Global); + set_union(Tmp.Relocs, Src.Relocs); + set_union(Tmp.Tls, Src.Tls); + set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols); + + size_t Count = IsPrimary ? HeaderEntriesNum : 0; + Count += Tmp.getIndexedEntriesNum(); + + if (Count * Config->Wordsize > Config->MipsGotSize) + return false; + + std::swap(Tmp, Dst); + return true; } void MipsGotSection::finalizeContents() { updateAllocSize(); } bool MipsGotSection::updateAllocSize() { - PageEntriesNum = 0; - for (std::pair &P : PageIndexMap) { - // For each output section referenced by GOT page relocations calculate - // and save into PageIndexMap 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. And take in account the case when the section intersects - // page boundaries. - P.second = PageEntriesNum; - PageEntriesNum += getMipsPageCount(P.first->Size); - } - Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) * - Config->Wordsize; + Size = HeaderEntriesNum * Config->Wordsize; + for (const FileGot &G : Gots) + Size += G.getEntriesNum() * Config->Wordsize; return false; } +template void MipsGotSection::build() { + if (Gots.empty()) + return; + + std::vector MergedGots(1); + + // For each GOT move non-preemptible symbols from the `Global` + // to `Local16` list. Preemptible symbol might become non-preemptible + // one if, for example, it gets a related copy relocation. + for (FileGot &Got : Gots) { + for (auto &P: Got.Global) + if (!P.first->IsPreemptible) + Got.Local16.insert({{P.first, 0}, 0}); + Got.Global.remove_if([&](const std::pair &P) { + return !P.first->IsPreemptible; + }); + } + + // For each GOT remove "reloc-only" entry if there is "global" + // entry for the same symbol. And add local entries which indexed + // using 32-bit value at the end of 16-bit entries. + for (FileGot &Got : Gots) { + Got.Relocs.remove_if([&](const std::pair &P) { + return Got.Global.count(P.first); + }); + set_union(Got.Local16, Got.Local32); + Got.Local32.clear(); + } + + // Evaluate number of "reloc-only" entries in the resulting GOT. + // To do that put all unique "reloc-only" and "global" entries + // from all GOTs to the future primary GOT. + FileGot *PrimGot = &MergedGots.front(); + for (FileGot &Got : Gots) { + set_union(PrimGot->Relocs, Got.Global); + set_union(PrimGot->Relocs, Got.Relocs); + Got.Relocs.clear(); + } + + // Evaluate number of "page" entries in each GOT. + for (FileGot &Got : Gots) { + for (std::pair &P : + Got.PagesMap) { + const OutputSection *OS = P.first; + uint64_t SecSize = 0; + for (BaseCommand *Cmd : OS->SectionCommands) { + if (auto *ISD = dyn_cast(Cmd)) + for (InputSection *IS : ISD->Sections) { + uint64_t Off = alignTo(SecSize, IS->Alignment); + SecSize = Off + IS->getSize(); + } + } + P.second.Count = getMipsPageCount(SecSize); + } + } + + // Merge GOTs. Try to join as much as possible GOTs but do not + // exceed maximum GOT size. In case of overflow create new GOT + // and continue merging. + for (FileGot &SrcGot : Gots) { + FileGot &DstGot = MergedGots.back(); + InputFile *File = SrcGot.File; + if (!tryMergeGots(DstGot, SrcGot, &DstGot == PrimGot)) { + MergedGots.emplace_back(); + std::swap(MergedGots.back(), SrcGot); + } + File->MipsGotIndex = MergedGots.size() - 1; + } + std::swap(Gots, MergedGots); + + // Reduce number of "reloc-only" entries in the primary GOT + // by substracting "global" entries exist in the primary GOT. + PrimGot = &Gots.front(); + PrimGot->Relocs.remove_if([&](const std::pair &P) { + return PrimGot->Global.count(P.first); + }); + + // Calculate indexes for each GOT entry. + size_t Index = HeaderEntriesNum; + for (FileGot &Got : Gots) { + Got.StartIndex = &Got == PrimGot ? 0 : Index; + for (std::pair &P : + Got.PagesMap) { + // For each output section referenced by GOT page relocations calculate + // and save into PagesMap 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. And take in account the case when the section intersects + // page boundaries. + P.second.FirstIndex = Index; + Index += P.second.Count; + } + for (auto &P: Got.Local16) + P.second = Index++; + for (auto &P: Got.Global) + P.second = Index++; + for (auto &P: Got.Relocs) + P.second = Index++; + for (auto &P: Got.Tls) + P.second = Index++; + for (auto &P: Got.DynTlsSymbols) { + P.second = Index; + Index += 2; + } + } + + // Update Symbol::GotIndex field to use this + // value later in the `sortMipsSymbols` function. + for (auto &P : PrimGot->Global) + P.first->GotIndex = P.second; + for (auto &P : PrimGot->Relocs) + P.first->GotIndex = P.second; + + // Create dynamic relocations. + for (FileGot &Got : Gots) { + // Create dynamic relocations for TLS entries. + for (std::pair &P : Got.Tls) { + Symbol *S = P.first; + uint64_t Offset = P.second * Config->Wordsize; + if (S->IsPreemptible) + InX::RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S); + } + for (std::pair &P : Got.DynTlsSymbols) { + Symbol *S = P.first; + uint64_t Offset = P.second * Config->Wordsize; + if (S == nullptr) { + if (!Config->Pic) + continue; + InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); + } else { + if (!P.first->IsPreemptible) + continue; + InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); + Offset += Config->Wordsize; + InX::RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S); + } + } + + // Do not create dynamic relocations for non-TLS + // entries in the primary GOT. + if (&Got == PrimGot) + continue; + + // Dynamic relocations for "global" entries. + for (const std::pair &P : Got.Global) { + uint64_t Offset = P.second * Config->Wordsize; + InX::RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first); + } + if (!Config->Pic) + continue; + // Dynamic relocations for "local" entries in case of PIC. + for (const std::pair &L : + Got.PagesMap) { + size_t PageCount = L.second.Count; + for (size_t PI = 0; PI < PageCount; ++PI) { + uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize; + InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first, + int64_t(PI * 0x10000)}); + } + } + for (const std::pair &P : Got.Local16) { + uint64_t Offset = P.second * Config->Wordsize; + InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, true, + P.first.first, P.first.second}); + } + } +} + bool MipsGotSection::empty() const { // We add the .got section to the result for dynamic MIPS target because // its address and properties are mentioned in the .dynamic section. return Config->Relocatable; } -uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); } +uint64_t MipsGotSection::getGp(const InputFile *F) const { + // For files without related GOT or files refer a primary GOT + // returns "common" _gp value. For secondary GOTs calculate + // individual _gp values. + if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0) + return ElfSym::MipsGp->getVA(0); + return this->getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize + + 0x7ff0; +} void MipsGotSection::writeTo(uint8_t *Buf) { // Set the MSB of the second GOT slot. This is not required by any @@ -831,49 +990,47 @@ // keep doing this for now. We really need to revisit this to see // if we had to do this. writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1)); - Buf += HeaderEntriesNum * Config->Wordsize; - // Write 'page address' entries to the local part of the GOT. - for (std::pair &L : PageIndexMap) { - size_t PageCount = getMipsPageCount(L.first->Size); - uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr); - for (size_t PI = 0; PI < PageCount; ++PI) { - uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize; - writeUint(Entry, FirstPageAddr + PI * 0x10000); - } - } - Buf += PageEntriesNum * Config->Wordsize; - auto AddEntry = [&](const GotEntry &SA) { - uint8_t *Entry = Buf; - Buf += Config->Wordsize; - const Symbol *Sym = SA.first; - uint64_t VA = Sym->getVA(SA.second); - if (Sym->StOther & STO_MIPS_MICROMIPS) - VA |= 1; - writeUint(Entry, VA); - }; - std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry); - std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry); - std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry); - // Initialize TLS-related GOT entries. If the entry has a corresponding - // dynamic relocations, leave it initialized by zero. Write down adjusted - // TLS symbol's values otherwise. To calculate the adjustments use offsets - // for thread-local storage. - // https://www.linux-mips.org/wiki/NPTL - if (TlsIndexOff != -1U && !Config->Pic) - writeUint(Buf + TlsIndexOff, 1); - for (const Symbol *B : TlsEntries) { - if (!B || B->IsPreemptible) - continue; - uint64_t VA = B->getVA(); - if (B->GotIndex != -1U) { - uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize; - writeUint(Entry, VA - 0x7000); + for (const FileGot &G : Gots) { + auto Write = [&](size_t I, const Symbol *S, int64_t A) { + uint64_t VA = A; + if (S) { + VA = S->getVA(A); + if (S->StOther & STO_MIPS_MICROMIPS) + VA |= 1; + } + writeUint(Buf + I * Config->Wordsize, VA); + }; + // Write 'page address' entries to the local part of the GOT. + for (const std::pair &L : + G.PagesMap) { + size_t PageCount = L.second.Count; + uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr); + for (size_t PI = 0; PI < PageCount; ++PI) + Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000); } - if (B->GlobalDynIndex != -1U) { - uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize; - writeUint(Entry, 1); - Entry += Config->Wordsize; - writeUint(Entry, VA - 0x8000); + // Local, global, TLS, reloc-only entries. + // If TLS entry has a corresponding dynamic relocations, leave it + // initialized by zero. Write down adjusted TLS symbol's values otherwise. + // To calculate the adjustments use offsets for thread-local storage. + // https://www.linux-mips.org/wiki/NPTL + for (const std::pair &P : G.Local16) + Write(P.second, P.first.first, P.first.second); + // Write VA to the primary GOT only. For secondary GOTs that + // will be done by REL32 dynamic relocations. + if (&G == &Gots.front()) + for (const std::pair &P : G.Global) + Write(P.second, P.first, 0); + for (const std::pair &P : G.Relocs) + Write(P.second, P.first, 0); + for (const std::pair &P : G.Tls) + Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000); + for (const std::pair &P : G.DynTlsSymbols) { + if (P.first == nullptr && !Config->Pic) + Write(P.second, nullptr, 1); + else if (P.first && !P.first->IsPreemptible) { + Write(P.second, nullptr, 1); + Write(P.second + 1, P.first, -0x8000); + } } } } @@ -1209,7 +1366,10 @@ int64_t DynamicReloc::computeAddend() const { if (UseSymVA) return Sym->getVA(Addend); - return Addend; + if (!OutputSec) + return Addend; + // See the comment in the DynamicReloc ctor. + return getMipsPageAddr(OutputSec->Addr) + Addend; } uint32_t DynamicReloc::getSymIndex() const { @@ -1263,17 +1423,6 @@ if (Config->IsRela) P->r_addend = Rel.computeAddend(); P->r_offset = Rel.getOffset(); - if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot) - // The MIPS GOT section contains dynamic relocations that correspond to TLS - // entries. These entries are placed after the global and local sections of - // the GOT. At the point when we create these relocations, the size of the - // global and local sections is unknown, so the offset that we store in the - // TLS entry's DynamicReloc is relative to the start of the TLS section of - // the GOT, rather than being relative to the start of the GOT. This line of - // code adds the size of the global and local sections to the virtual - // address computed by getOffset() in order to adjust it into the TLS - // section. - P->r_offset += InX::MipsGot->getTlsOffset(); P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); } @@ -1512,10 +1661,8 @@ const SymbolTableEntry &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.Sym->IsInGlobalMipsGot; - bool RIsInLocalGot = !R.Sym->IsInGlobalMipsGot; - if (LIsInLocalGot || RIsInLocalGot) - return !RIsInLocalGot; + if (!L.Sym->isInGot() || !R.Sym->isInGot()) + return !L.Sym->isInGot(); return L.Sym->GotIndex < R.Sym->GotIndex; } @@ -2718,6 +2865,11 @@ template void PltSection::addEntry(Symbol &Sym); template void PltSection::addEntry(Symbol &Sym); +template void MipsGotSection::build(); +template void MipsGotSection::build(); +template void MipsGotSection::build(); +template void MipsGotSection::build(); + template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1576,6 +1576,9 @@ if (errorCount()) return; + if (InX::MipsGot) + InX::MipsGot->build(); + removeUnusedSyntheticSections(); sortSections(); Index: test/ELF/Inputs/mips-mgot-1.s =================================================================== --- /dev/null +++ test/ELF/Inputs/mips-mgot-1.s @@ -0,0 +1,10 @@ + .text + .global foo1 +foo1: + addiu $2, $2, %gottprel(tls0) # tls got entry + addiu $2, $2, %gottprel(tls1) # tls got entry + + .section .tdata,"awT",%progbits + .global tls1 +tls1: + .word 0 Index: test/ELF/Inputs/mips-mgot-2.s =================================================================== --- /dev/null +++ test/ELF/Inputs/mips-mgot-2.s @@ -0,0 +1,17 @@ + .text + .global foo2 +foo2: + lw $2, %got(.data)($gp) # page entry + addi $2, $2, %lo(.data) + lw $2, %call16(foo0)($gp) # global entry + lw $2, %call16(foo2)($gp) # global entry + addiu $2, $2, %tlsgd(tls0) # tls gd entry + addiu $2, $2, %gottprel(tls0) # tls got entry + + .data + .space 0x20000 + + .section .tdata,"awT",%progbits + .global tls2 +tls2: + .word 0 Index: test/ELF/mips-dynamic.s =================================================================== --- test/ELF/mips-dynamic.s +++ test/ELF/mips-dynamic.s @@ -99,8 +99,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-got-script.s =================================================================== --- test/ELF/mips-got-script.s +++ test/ELF/mips-got-script.s @@ -7,8 +7,8 @@ # REQUIRES: mips -# CHECK: 0x7000000A MIPS_LOCAL_GOTNO 5 -# ^-- 2 * header + 3 local entries +# CHECK: 0x7000000A MIPS_LOCAL_GOTNO 4 +# ^-- 2 * header + 2 local entries # CHECK: Local entries [ # CHECK-NEXT: Entry { # CHECK-NEXT: Address: @@ -22,12 +22,6 @@ # CHECK-NEXT: Initial: 0x10000 # ^-- loc2 # CHECK-NEXT: } -# CHECK-NEXT: Entry { -# CHECK-NEXT: Address: -# CHECK-NEXT: Access: -32736 -# CHECK-NEXT: Initial: 0x20000 -# ^-- redundant -# CHECK-NEXT: } # CHECK-NEXT: ] .text Index: test/ELF/mips-got-weak.s =================================================================== --- test/ELF/mips-got-weak.s +++ test/ELF/mips-got-weak.s @@ -3,15 +3,15 @@ # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -shared -o %t1.so # RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t1.so \ -# RUN: | FileCheck -check-prefix=NOSYM %s +# RUN: | FileCheck -check-prefixes=CHECK,NOSYM %s # RUN: ld.lld %t.o -shared -Bsymbolic -o %t2.so # RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t2.so \ -# RUN: | FileCheck -check-prefix=SYM %s +# RUN: | FileCheck -check-prefixes=CHECK,SYM %s # REQUIRES: mips -# NOSYM: Relocations [ -# NOSYM-NEXT: ] +# CHECK: Relocations [ +# CHECK-NEXT: ] # NOSYM: Symbol { # NOSYM: Name: foo @@ -22,17 +22,19 @@ # NOSYM-NEXT: Other: 0 # NOSYM-NEXT: Section: .data # NOSYM-NEXT: } -# NOSYM-NEXT: Symbol { -# NOSYM-NEXT: Name: bar -# NOSYM-NEXT: Value: 0x0 -# NOSYM-NEXT: Size: 0 -# NOSYM-NEXT: Binding: Weak -# NOSYM-NEXT: Type: None -# NOSYM-NEXT: Other: 0 -# NOSYM-NEXT: Section: Undefined -# NOSYM-NEXT: } -# NOSYM-NEXT: Symbol { -# NOSYM-NEXT: Name: sym + +# CHECK: Symbol { +# CHECK: Name: bar +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Weak +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } + +# NOSYM: Symbol { +# NOSYM: Name: sym # NOSYM-NEXT: Value: 0x20004 # NOSYM-NEXT: Size: 0 # NOSYM-NEXT: Binding: Global @@ -40,30 +42,48 @@ # NOSYM-NEXT: Other: 0 # NOSYM-NEXT: Section: .data # NOSYM-NEXT: } -# NOSYM-NEXT: ] -# NOSYM: 0x70000011 MIPS_SYMTABNO 4 -# NOSYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 2 -# NOSYM-NEXT: 0x70000013 MIPS_GOTSYM 0x1 +# CHECK: 0x70000011 MIPS_SYMTABNO 4 -# NOSYM: Primary GOT { -# NOSYM-NEXT: Canonical gp value: -# NOSYM-NEXT: Reserved entries [ -# NOSYM-NEXT: Entry { -# NOSYM-NEXT: Address: -# NOSYM-NEXT: Access: -32752 -# NOSYM-NEXT: Initial: 0x0 -# NOSYM-NEXT: Purpose: Lazy resolver -# NOSYM-NEXT: } -# NOSYM-NEXT: Entry { -# NOSYM-NEXT: Address: -# NOSYM-NEXT: Access: -32748 -# NOSYM-NEXT: Initial: 0x80000000 -# NOSYM-NEXT: Purpose: Module pointer (GNU extension) -# NOSYM-NEXT: } -# NOSYM-NEXT: ] -# NOSYM-NEXT: Local entries [ +# SYM: 0x7000000A MIPS_LOCAL_GOTNO 4 +# SYM: 0x70000013 MIPS_GOTSYM 0x3 + +# NOSYM: 0x7000000A MIPS_LOCAL_GOTNO 2 +# NOSYM: 0x70000013 MIPS_GOTSYM 0x1 + +# CHECK: Primary GOT { +# CHECK-NEXT: Canonical gp value: +# CHECK-NEXT: Reserved entries [ +# CHECK: ] + +# SYM: Local entries [ +# SYM-NEXT: Entry { +# SYM-NEXT: Address: +# SYM-NEXT: Access: -32744 +# SYM-NEXT: Initial: 0x20000 +# SYM-NEXT: } +# SYM-NEXT: Entry { +# SYM-NEXT: Address: +# SYM-NEXT: Access: -32740 +# SYM-NEXT: Initial: 0x20004 +# SYM-NEXT: } +# SYM-NEXT: ] + +# NOSYM: Local entries [ # NOSYM-NEXT: ] + +# SYM-NEXT: Global entries [ +# SYM-NEXT: Entry { +# SYM-NEXT: Address: +# SYM-NEXT: Access: -32736 +# SYM-NEXT: Initial: 0x0 +# SYM-NEXT: Value: 0x0 +# SYM-NEXT: Type: None +# SYM-NEXT: Section: Undefined +# SYM-NEXT: Name: bar +# SYM-NEXT: } +# SYM-NEXT: ] + # NOSYM-NEXT: Global entries [ # NOSYM-NEXT: Entry { # NOSYM-NEXT: Address: @@ -93,68 +113,9 @@ # NOSYM-NEXT: Name: sym # NOSYM-NEXT: } # NOSYM-NEXT: ] -# NOSYM-NEXT: Number of TLS and multi-GOT entries: 0 -# NOSYM-NEXT: } - -# SYM: Relocations [ -# SYM-NEXT: ] - -# SYM: Symbol { -# SYM: Name: bar -# SYM-NEXT: Value: 0x0 -# SYM-NEXT: Size: 0 -# SYM-NEXT: Binding: Weak -# SYM-NEXT: Type: None -# SYM-NEXT: Other: 0 -# SYM-NEXT: Section: Undefined -# SYM-NEXT: } -# SYM-NEXT: ] - -# SYM: 0x70000011 MIPS_SYMTABNO 4 -# SYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 4 -# SYM-NEXT: 0x70000013 MIPS_GOTSYM 0x3 - -# SYM: Primary GOT { -# SYM-NEXT: Canonical gp value: -# SYM-NEXT: Reserved entries [ -# SYM-NEXT: Entry { -# SYM-NEXT: Address: -# SYM-NEXT: Access: -32752 -# SYM-NEXT: Initial: 0x0 -# SYM-NEXT: Purpose: Lazy resolver -# SYM-NEXT: } -# SYM-NEXT: Entry { -# SYM-NEXT: Address: -# SYM-NEXT: Access: -32748 -# SYM-NEXT: Initial: 0x80000000 -# SYM-NEXT: Purpose: Module pointer (GNU extension) -# SYM-NEXT: } -# SYM-NEXT: ] -# SYM-NEXT: Local entries [ -# SYM-NEXT: Entry { -# SYM-NEXT: Address: -# SYM-NEXT: Access: -32744 -# SYM-NEXT: Initial: 0x20000 -# SYM-NEXT: } -# SYM-NEXT: Entry { -# SYM-NEXT: Address: -# SYM-NEXT: Access: -32740 -# SYM-NEXT: Initial: 0x20004 -# SYM-NEXT: } -# SYM-NEXT: ] -# SYM-NEXT: Global entries [ -# SYM-NEXT: Entry { -# SYM-NEXT: Address: -# SYM-NEXT: Access: -32736 -# SYM-NEXT: Initial: 0x0 -# SYM-NEXT: Value: 0x0 -# SYM-NEXT: Type: None -# SYM-NEXT: Section: Undefined -# SYM-NEXT: Name: bar -# SYM-NEXT: } -# SYM-NEXT: ] -# SYM-NEXT: Number of TLS and multi-GOT entries: 0 -# SYM-NEXT: } + +# CHECK: Number of TLS and multi-GOT entries: 0 +# CHECK-NEXT: } .text .global sym Index: test/ELF/mips-mgot.s =================================================================== --- /dev/null +++ test/ELF/mips-mgot.s @@ -0,0 +1,129 @@ +# Check MIPS multi-GOT layout. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t0.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-mgot-1.s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-mgot-2.s -o %t2.o +# RUN: ld.lld -shared -mips-got-size 52 %t0.o %t1.o %t2.o -o %t.so +# RUN: llvm-objdump -s -section=.got -t %t.so | FileCheck %s +# RUN: llvm-readobj -r -dt -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s + +# REQUIRES: mips + +# CHECK: Contents of section .got: +# CHECK-NEXT: 60000 00000000 80000000 00010000 00010030 +# CHECK-NEXT: 60010 00020000 00030000 00040000 00050000 +# CHECK-NEXT: 60020 00060000 00070000 00000000 00000000 +# CHECK-NEXT: 60030 00000004 00000000 00000000 00000000 +# CHECK-NEXT: 60040 00000000 00020000 00030000 00040000 +# CHECK-NEXT: 60050 00050000 00060000 00070000 00000000 +# CHECK-NEXT: 60060 00000000 00000000 00000000 00000000 + +# CHECK: SYMBOL TABLE: +# CHECK: 00000000 l .tdata 00000000 loc0 +# CHECK: 00010000 .text 00000000 foo0 +# CHECK: 00000000 g .tdata 00000000 tls0 +# CHECK: 00010020 .text 00000000 foo1 +# CHECK: 00000004 g .tdata 00000000 tls1 +# CHECK: 00010030 .text 00000000 foo2 +# CHECK: 00000008 g .tdata 00000000 tls2 + +# GOT: Relocations [ +# GOT-NEXT: Section (7) .rel.dyn { +# GOT-NEXT: 0x60010 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60014 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60018 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x6001C R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60020 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60024 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60044 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60048 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x6004C R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60050 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60054 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60058 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60028 R_MIPS_REL32 foo0 0x0 +# GOT-NEXT: 0x6005C R_MIPS_REL32 foo0 0x0 +# GOT-NEXT: 0x60060 R_MIPS_REL32 foo2 0x0 +# GOT-NEXT: 0x6003C R_MIPS_TLS_DTPMOD32 - 0x0 +# GOT-NEXT: 0x60030 R_MIPS_TLS_TPREL32 tls1 0x0 +# GOT-NEXT: 0x6002C R_MIPS_TLS_TPREL32 tls0 0x0 +# GOT-NEXT: 0x60034 R_MIPS_TLS_DTPMOD32 tls0 0x0 +# GOT-NEXT: 0x60038 R_MIPS_TLS_DTPREL32 tls0 0x0 +# GOT-NEXT: 0x60064 R_MIPS_TLS_TPREL32 tls0 0x0 +# GOT-NEXT: 0x60068 R_MIPS_TLS_DTPMOD32 tls0 0x0 +# GOT-NEXT: 0x6006C R_MIPS_TLS_DTPREL32 tls0 0x0 +# GOT-NEXT: } +# GOT-NEXT: ] + +# GOT: DynamicSymbols [ +# GOT: Symbol { +# GOT: Name: foo0 +# GOT-NEXT: Value: 0x10000 +# GOT: } +# GOT-NEXT: Symbol { +# GOT-NEXT: Name: foo2 +# GOT-NEXT: Value: 0x10030 +# GOT: } +# GOT-NEXT: ] + +# GOT: Primary GOT { +# GOT-NEXT: Canonical gp value: 0x67FF0 +# GOT-NEXT: Reserved entries [ +# GOT-NEXT: Entry { +# GOT-NEXT: Address: +# GOT-NEXT: Access: -32752 +# GOT-NEXT: Initial: 0x0 +# GOT-NEXT: Purpose: Lazy resolver +# GOT-NEXT: } +# GOT-NEXT: Entry { +# GOT-NEXT: Address: +# GOT-NEXT: Access: -32748 +# GOT-NEXT: Initial: 0x80000000 +# GOT-NEXT: Purpose: Module pointer (GNU extension) +# GOT-NEXT: } +# GOT-NEXT: ] +# GOT-NEXT: Local entries [ +# GOT-NEXT: ] +# GOT-NEXT: Global entries [ +# GOT-NEXT: Entry { +# GOT-NEXT: Address: +# GOT-NEXT: Access: -32744 +# GOT-NEXT: Initial: 0x10000 +# GOT-NEXT: Value: 0x10000 +# GOT-NEXT: Type: None +# GOT-NEXT: Section: .text +# GOT-NEXT: Name: foo0 +# GOT-NEXT: } +# GOT-NEXT: Entry { +# GOT-NEXT: Address: +# GOT-NEXT: Access: -32740 +# GOT-NEXT: Initial: 0x10030 +# GOT-NEXT: Value: 0x10030 +# GOT-NEXT: Type: None +# GOT-NEXT: Section: .text +# GOT-NEXT: Name: foo2 +# GOT-NEXT: } +# GOT-NEXT: ] +# GOT-NEXT: Number of TLS and multi-GOT entries: 24 +# GOT-NEXT: } + + .text + .global foo0 +foo0: + lw $2, %got(.data)($gp) # page entry + addi $2, $2, %lo(.data) + lw $2, %call16(foo0)($gp) # global entry + addiu $2, $2, %tlsgd(tls0) # tls gd entry + addiu $2, $2, %gottprel(tls0) # tls got entry + addiu $2, $2, %tlsldm(loc0) # tls ld entry + + .data + .space 0x20000 + + .section .tdata,"awT",%progbits + .global tls0 +tls0: +loc0: + .word 0 Index: test/ELF/mips-plt-copy.s =================================================================== --- test/ELF/mips-plt-copy.s +++ test/ELF/mips-plt-copy.s @@ -12,12 +12,12 @@ # 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-DAG: 0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0 +# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_COPY data1 0x0 # CHECK-NEXT: } # CHECK-NEXT: Section ({{.*}}) .rel.plt { -# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0 -# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo1 0x0 +# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0 +# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo1 0x0 # CHECK-NEXT: } # CHECK-NEXT: ] 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: 0x[[FOO1:[0-9A-F]+]] # 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: } @@ -48,7 +48,7 @@ # CHECK-NEXT: Entry { # CHECK-NEXT: Address: # CHECK-NEXT: Initial: -# CHECK-NEXT: Value: 0x20050 +# CHECK-NEXT: Value: 0x[[FOO1]] # CHECK-NEXT: Type: Function # CHECK-NEXT: Section: Undefined # CHECK-NEXT: Name: foo1 Index: test/ELF/mips-tls-64.s =================================================================== --- test/ELF/mips-tls-64.s +++ test/ELF/mips-tls-64.s @@ -16,18 +16,18 @@ # REQUIRES: mips # DIS: __start: -# DIS-NEXT: 20000: 24 62 80 20 addiu $2, $3, -32736 -# DIS-NEXT: 20004: 24 62 80 30 addiu $2, $3, -32720 -# DIS-NEXT: 20008: 24 62 80 38 addiu $2, $3, -32712 -# DIS-NEXT: 2000c: 24 62 80 48 addiu $2, $3, -32696 -# DIS-NEXT: 20010: 24 62 80 58 addiu $2, $3, -32680 +# DIS-NEXT: 20000: 24 62 80 30 addiu $2, $3, -32720 +# DIS-NEXT: 20004: 24 62 80 20 addiu $2, $3, -32736 +# DIS-NEXT: 20008: 24 62 80 40 addiu $2, $3, -32704 +# DIS-NEXT: 2000c: 24 62 80 50 addiu $2, $3, -32688 +# DIS-NEXT: 20010: 24 62 80 28 addiu $2, $3, -32728 # DIS: Contents of section .got: # DIS-NEXT: 30010 00000000 00000000 80000000 00000000 -# DIS-NEXT: 30020 00000000 00000000 00000000 00000000 -# DIS-NEXT: 30030 00000000 00000000 00000000 00000001 -# DIS-NEXT: 30040 00000000 00000000 00000000 00000001 -# DIS-NEXT: 30050 ffffffff ffff8004 ffffffff ffff9004 +# DIS-NEXT: 30020 00000000 00000000 ffffffff ffff9004 +# DIS-NEXT: 30030 00000000 00000000 00000000 00000000 +# DIS-NEXT: 30040 00000000 00000001 00000000 00000000 +# DIS-NEXT: 30050 00000000 00000001 ffffffff ffff8004 # DIS: 0000000000000000 l .tdata 00000000 loc # DIS: 0000000000000004 g .tdata 00000000 bar @@ -35,9 +35,9 @@ # CHECK: Relocations [ # CHECK-NEXT: Section (7) .rel.dyn { -# CHECK-NEXT: 0x30020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 -# CHECK-NEXT: 0x30028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 -# CHECK-NEXT: 0x30030 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# CHECK-NEXT: 0x30020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# CHECK-NEXT: 0x30030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# CHECK-NEXT: 0x30038 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: Primary GOT { @@ -49,31 +49,31 @@ # CHECK-NEXT: Global entries [ # CHECK-NEXT: ] # CHECK-NEXT: Number of TLS and multi-GOT entries: 8 -# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo -# ^-- -32728 R_MIPS_TLS_DTPREL64 foo -# ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo -# ^-- -32712 R_MIPS_TLS_LDM 1 loc -# ^-- -32704 0 loc -# ^-- -32696 R_MIPS_TLS_GD 1 bar -# ^-- -32688 VA - 0x8000 bar -# ^-- -32680 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar +# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo +# ^-- -32728 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar +# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo +# ^-- -32712 R_MIPS_TLS_DTPREL64 foo +# ^-- -32704 R_MIPS_TLS_LDM 1 loc +# ^-- -32696 0 loc +# ^-- -32688 R_MIPS_TLS_GD 1 bar +# ^-- -32680 VA - 0x8000 bar # DIS-SO: Contents of section .got: # DIS-SO-NEXT: 20000 00000000 00000000 80000000 00000000 -# DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000000 +# DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000004 # DIS-SO-NEXT: 20020 00000000 00000000 00000000 00000000 # DIS-SO-NEXT: 20030 00000000 00000000 00000000 00000000 # DIS-SO-NEXT: 20040 00000000 00000000 00000000 00000000 # SO: Relocations [ # SO-NEXT: Section (7) .rel.dyn { -# SO-NEXT: 0x20028 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0 -# SO-NEXT: 0x20038 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 -# SO-NEXT: 0x20040 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 -# SO-NEXT: 0x20048 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 -# SO-NEXT: 0x20010 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 -# SO-NEXT: 0x20018 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 -# SO-NEXT: 0x20020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# SO-NEXT: 0x20030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0 +# SO-NEXT: 0x20010 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# SO-NEXT: 0x20020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# SO-NEXT: 0x20028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# SO-NEXT: 0x20018 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 +# SO-NEXT: 0x20040 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 +# SO-NEXT: 0x20048 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 # SO-NEXT: } # SO-NEXT: ] # SO-NEXT: Primary GOT { @@ -85,14 +85,14 @@ # SO-NEXT: Global entries [ # SO-NEXT: ] # SO-NEXT: Number of TLS and multi-GOT entries: 8 -# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo -# ^-- -32728 R_MIPS_TLS_DTPREL64 foo -# ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo -# ^-- -32712 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD64 loc -# ^-- -32704 0 loc -# ^-- -32696 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 bar -# ^-- -32688 R_MIPS_TLS_DTPREL64 bar -# ^-- -32680 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 bar +# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo +# ^-- -32728 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 bar +# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo +# ^-- -32712 R_MIPS_TLS_DTPREL64 foo +# ^-- -32704 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD64 loc +# ^-- -32696 0 loc +# ^-- -32688 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 bar +# ^-- -32680 R_MIPS_TLS_DTPREL64 bar .text .global __start Index: test/ELF/mips-tls-static.s =================================================================== --- test/ELF/mips-tls-static.s +++ test/ELF/mips-tls-static.s @@ -10,8 +10,8 @@ # CHECK: Contents of section .data: # CHECK-NEXT: 30000 0002000c ffff8004 ffff9004 # CHECK: Contents of section .got: -# CHECK-NEXT: 30010 00000000 80000000 00000001 ffff8000 -# CHECK-NEXT: 30020 00000001 00000000 ffff9000 +# CHECK-NEXT: 30010 00000000 80000000 ffff9000 00000001 +# CHECK-NEXT: 30020 ffff8000 00000001 00000000 # # CHECK: SYMBOL TABLE: # CHECK: 0002000c .text 00000000 __tls_get_addr Index: test/ELF/mips-tls.s =================================================================== --- test/ELF/mips-tls.s +++ test/ELF/mips-tls.s @@ -16,16 +16,16 @@ # REQUIRES: mips # DIS: __start: -# DIS-NEXT: 20000: 24 62 80 18 addiu $2, $3, -32744 -# DIS-NEXT: 20004: 24 62 80 20 addiu $2, $3, -32736 -# DIS-NEXT: 20008: 24 62 80 24 addiu $2, $3, -32732 -# DIS-NEXT: 2000c: 24 62 80 2c addiu $2, $3, -32724 -# DIS-NEXT: 20010: 24 62 80 34 addiu $2, $3, -32716 +# DIS-NEXT: 20000: 24 62 80 20 addiu $2, $3, -32736 +# DIS-NEXT: 20004: 24 62 80 18 addiu $2, $3, -32744 +# DIS-NEXT: 20008: 24 62 80 28 addiu $2, $3, -32728 +# DIS-NEXT: 2000c: 24 62 80 30 addiu $2, $3, -32720 +# DIS-NEXT: 20010: 24 62 80 1c addiu $2, $3, -32740 # DIS: Contents of section .got: -# DIS-NEXT: 30010 00000000 80000000 00000000 00000000 -# DIS-NEXT: 30020 00000000 00000001 00000000 00000001 -# DIS-NEXT: 30030 ffff8004 ffff9004 +# DIS-NEXT: 30010 00000000 80000000 00000000 ffff9004 +# DIS-NEXT: 30020 00000000 00000000 00000001 00000000 +# DIS-NEXT: 30030 00000001 ffff8004 # DIS: 00000000 l .tdata 00000000 loc # DIS: 00000004 g .tdata 00000000 bar @@ -33,9 +33,9 @@ # CHECK: Relocations [ # CHECK-NEXT: Section (7) .rel.dyn { -# CHECK-NEXT: 0x30018 R_MIPS_TLS_DTPMOD32 foo 0x0 -# CHECK-NEXT: 0x3001C R_MIPS_TLS_DTPREL32 foo 0x0 -# CHECK-NEXT: 0x30020 R_MIPS_TLS_TPREL32 foo 0x0 +# CHECK-NEXT: 0x30018 R_MIPS_TLS_TPREL32 foo 0x0 +# CHECK-NEXT: 0x30020 R_MIPS_TLS_DTPMOD32 foo 0x0 +# CHECK-NEXT: 0x30024 R_MIPS_TLS_DTPREL32 foo 0x0 # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: Primary GOT { @@ -47,29 +47,29 @@ # CHECK-NEXT: Global entries [ # CHECK-NEXT: ] # CHECK-NEXT: Number of TLS and multi-GOT entries: 8 -# ^-- -32744 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo -# ^-- -32740 R_MIPS_TLS_DTPREL32 foo -# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo -# ^-- -32732 R_MIPS_TLS_LDM 1 loc -# ^-- -32728 0 loc -# ^-- -32724 R_MIPS_TLS_GD 1 bar -# ^-- -32720 VA - 0x8000 bar -# ^-- -32716 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar +# ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo +# ^-- -32740 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar +# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo +# ^-- -32732 R_MIPS_TLS_DTPREL32 foo +# ^-- -32728 R_MIPS_TLS_LDM 1 loc +# ^-- -32724 0 loc +# ^-- -32720 R_MIPS_TLS_GD 1 bar +# ^-- -32716 VA - 0x8000 bar # DIS-SO: Contents of section .got: -# DIS-SO-NEXT: 20000 00000000 80000000 00000000 00000000 +# DIS-SO-NEXT: 20000 00000000 80000000 00000000 00000004 # DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000000 # DIS-SO-NEXT: 20020 00000000 00000000 # SO: Relocations [ # SO-NEXT: Section (7) .rel.dyn { -# SO-NEXT: 0x20014 R_MIPS_TLS_DTPMOD32 - 0x0 -# SO-NEXT: 0x2001C R_MIPS_TLS_DTPMOD32 bar 0x0 -# SO-NEXT: 0x20020 R_MIPS_TLS_DTPREL32 bar 0x0 -# SO-NEXT: 0x20024 R_MIPS_TLS_TPREL32 bar 0x0 -# SO-NEXT: 0x20008 R_MIPS_TLS_DTPMOD32 foo 0x0 -# SO-NEXT: 0x2000C R_MIPS_TLS_DTPREL32 foo 0x0 -# SO-NEXT: 0x20010 R_MIPS_TLS_TPREL32 foo 0x0 +# SO-NEXT: 0x20018 R_MIPS_TLS_DTPMOD32 - 0x0 +# SO-NEXT: 0x20008 R_MIPS_TLS_TPREL32 foo 0x0 +# SO-NEXT: 0x20010 R_MIPS_TLS_DTPMOD32 foo 0x0 +# SO-NEXT: 0x20014 R_MIPS_TLS_DTPREL32 foo 0x0 +# SO-NEXT: 0x2000C R_MIPS_TLS_TPREL32 bar 0x0 +# SO-NEXT: 0x20020 R_MIPS_TLS_DTPMOD32 bar 0x0 +# SO-NEXT: 0x20024 R_MIPS_TLS_DTPREL32 bar 0x0 # SO-NEXT: } # SO-NEXT: ] # SO-NEXT: Primary GOT { @@ -81,14 +81,14 @@ # SO-NEXT: Global entries [ # SO-NEXT: ] # SO-NEXT: Number of TLS and multi-GOT entries: 8 -# ^-- -32744 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo -# ^-- -32740 R_MIPS_TLS_DTPREL32 foo -# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo -# ^-- -32732 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD32 loc -# ^-- -32728 0 loc -# ^-- -32724 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 bar -# ^-- -32720 R_MIPS_TLS_DTPREL32 bar -# ^-- -32716 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 bar +# ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo +# ^-- -32740 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 bar +# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo +# ^-- -32732 R_MIPS_TLS_DTPREL32 foo +# ^-- -32728 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD32 loc +# ^-- -32724 0 loc +# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 bar +# ^-- -32716 R_MIPS_TLS_DTPREL32 bar .text .global __start