Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -160,6 +160,7 @@ uint64_t ErrorLimit = 20; uint64_t ImageBase; uint64_t MaxPageSize; + uint64_t MipsGotSize; uint64_t ZStackSize; unsigned LTOPartitions; unsigned LTOO; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -649,6 +649,7 @@ Config->LTOO = getInteger(Args, OPT_lto_O, 2); Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1); Config->MapFile = getString(Args, OPT_Map); + Config->MipsGotSize = getInteger(Args, OPT_mips_got_size, 0xfff0); Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique); Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version); Config->Nostdlib = Args.hasArg(OPT_nostdlib); 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 lld; Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -95,6 +95,9 @@ // Cache for toString(). Only toString() should use this member. mutable std::string ToStringCache; + // Index of MIPS GOT built for this file. + size_t MipsGotIndex = -1; + protected: InputFile(Kind K, MemoryBufferRef M); std::vector Sections; Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -405,8 +405,9 @@ return OS->FirstInPtLoad->Addr; } -static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, - const SymbolBody &Body, RelExpr Expr) { +static uint64_t getRelocTargetVA(const InputFile &File, uint32_t Type, + int64_t A, uint64_t P, const SymbolBody &Body, + RelExpr Expr) { switch (Expr) { case R_ABS: case R_RELAX_GOT_PC_NOPIC: @@ -440,15 +441,15 @@ case R_TLSDESC_CALL: llvm_unreachable("cannot relocate hint relocs"); case R_MIPS_GOTREL: - return Body.getVA(A) - InX::MipsGot->getGp(); + return Body.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 // formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - uint64_t V = InX::MipsGot->getGp() + A - P; + uint64_t V = InX::MipsGot->getGp(&File) + A - P; if (Type == R_MIPS_LO16) V += 4; return V; @@ -457,21 +458,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(Body, A) - - InX::MipsGot->getGp(); + return InX::MipsGot->getVA() + + InX::MipsGot->getPageEntryOffset(File, Body, 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->getBodyEntryOffset(Body, A) - - InX::MipsGot->getGp(); + return InX::MipsGot->getVA() + + InX::MipsGot->getBodyEntryOffset(File, Body, A) - + InX::MipsGot->getGp(&File); case R_MIPS_TLSGD: - return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() + - InX::MipsGot->getGlobalDynOffset(Body) - InX::MipsGot->getGp(); + return InX::MipsGot->getVA() + + InX::MipsGot->getGlobalDynOffset(File, Body) - + 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: if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) @@ -581,7 +585,7 @@ uint64_t SymVA = 0; if (!Sym.isTls() || Out::TlsPhdr) SymVA = SignExtend64( - getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS)); + getRelocTargetVA(*File, Type, Addend, AddrLoc, Sym, R_ABS)); Target->relocateOne(BufLoc, Type, SymVA); } } @@ -622,7 +626,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 @@ -404,3 +404,7 @@ // Aliases for ignored options def alias_version_script_version_script: J<"version-script=">, Alias; + +// Hidden option used for testing MIPS multi-GOT implementation. +def mips_got_size: S<"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 @@ -101,28 +101,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(uint32_t Type, SymbolBody &Body, InputSectionBase &C, uint64_t Offset, int64_t Addend, RelExpr Expr) { if (Expr == R_MIPS_TLSLD) { - if (InX::MipsGot->addTlsIndex() && Config->Pic) - In::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot, - InX::MipsGot->getTlsIndexOff(), false, - nullptr, 0}); + InX::MipsGot->addTlsIndex(*C.File); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } - if (Expr == R_MIPS_TLSGD) { - if (InX::MipsGot->addDynTlsEntry(Body) && Body.isPreemptible()) { - uint64_t Off = InX::MipsGot->getGlobalDynOffset(Body); - In::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Body, 0}); - if (Body.isPreemptible()) - In::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot, - Off + Config->Wordsize, false, &Body, 0}); - } + InX::MipsGot->addDynTlsEntry(*C.File, Body); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } @@ -202,7 +190,7 @@ if (Config->EMachine == EM_ARM) return handleARMTlsRelocation(Type, Body, C, Offset, Addend, Expr); if (Config->EMachine == EM_MIPS) - return handleMipsTlsRelocation(Type, Body, C, Offset, Addend, Expr); + return handleMipsTlsRelocation(Type, Body, C, Offset, Addend, Expr); bool IsPreemptible = isPreemptible(Body, Type); if (isRelExprOneOf(Expr) && @@ -891,10 +879,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(Body, Addend, Expr); - if (Body.isTls() && Body.isPreemptible()) - In::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot, - Body.getGotOffset(), false, &Body, 0}); + InX::MipsGot->addEntry(*Sec.File, Body, Addend, Expr); } else if (!Body.isInGot()) { addGotEntry(Body, Preemptible); } @@ -927,7 +912,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(Body, Addend, Expr); + InX::MipsGot->addEntry(*Sec.File, Body, Addend, Expr); continue; } Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -112,12 +112,6 @@ // 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; - - // 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/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -125,8 +125,8 @@ SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type) : SymbolKind(K), NeedsCopy(false), NeedsPltAddr(false), IsLocal(IsLocal), - IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), - IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {} + IsInIplt(false), IsInIgot(false), Type(Type), StOther(StOther), + Name(Name) {} // 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. Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -174,12 +174,22 @@ void updateAllocSize() override; void finalizeContents() override; bool empty() const override; - void addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr); - bool addDynTlsEntry(SymbolBody &Sym); - bool addTlsIndex(); - uint64_t getPageEntryOffset(const SymbolBody &B, int64_t Addend) const; - uint64_t getBodyEntryOffset(const SymbolBody &B, int64_t Addend) const; - uint64_t getGlobalDynOffset(const SymbolBody &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, SymbolBody &Sym, int64_t Addend, RelExpr Expr); + void addDynTlsEntry(InputFile &File, SymbolBody &Sym); + void addTlsIndex(InputFile &File); + + uint64_t getPageEntryOffset(const InputFile &F, const SymbolBody &B, + int64_t Addend) const; + uint64_t getBodyEntryOffset(const InputFile &F, const SymbolBody &B, + int64_t Addend) const; + uint64_t getGlobalDynOffset(const InputFile &F, const SymbolBody &B) 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 @@ -191,13 +201,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 @@ -236,32 +241,101 @@ // 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; + + // Map output sections referenced by MIPS GOT relocations + // to the first index of "Page" entries allocated for this section. + llvm::SmallMapVector PageIndexMap; + // 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; + + size_t getEntriesNum() const; + size_t getPageEntriesNum() const; + size_t getIndexEntriesNum() const; + + bool isOverflow() const; + }; + + // Container of GOT created for each input file. + // After building a final series of GOTs this container + // holds primary ans secondaty 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 { @@ -315,7 +389,15 @@ uint64_t OffsetInSec, bool UseSymVA, SymbolBody *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(uint32_t 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; int64_t getAddend() const; @@ -330,6 +412,7 @@ uint64_t OffsetInSec; bool UseSymVA; int64_t Addend; + const OutputSection *OutputSec; }; template class DynamicSection final : public SyntheticSection { Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -27,6 +27,7 @@ #include "Threads.h" #include "Writer.h" #include "lld/Config/Version.h" +#include "llvm/ADT/SetOperations.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Dwarf.h" @@ -667,93 +668,35 @@ : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, ".got") {} -void MipsGotSection::addEntry(SymbolBody &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 +void MipsGotSection::addEntry(InputFile &File, SymbolBody &Sym, int64_t Addend, + RelExpr Expr) { + FileGot &G = getGot(File); 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 *DefSym = cast(&Sym); - PageIndexMap.insert({DefSym->Section->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 = [&](SymbolBody &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); - } -} - -bool MipsGotSection::addDynTlsEntry(SymbolBody &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; + G.PageIndexMap.insert({DefSym->Section->getOutputSection(), 0}); + } 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}); } -// 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::addDynTlsEntry(InputFile &File, SymbolBody &Sym) { + getGot(File).DynTlsSymbols.insert({&Sym, 0}); +} + +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) { @@ -764,73 +707,272 @@ return (Size + 0xfffe) / 0xffff + 1; } -uint64_t MipsGotSection::getPageEntryOffset(const SymbolBody &B, +size_t MipsGotSection::FileGot::getPageEntriesNum() const { + size_t Num = 0; + for (const std::pair &P : PageIndexMap) + Num += getMipsPageCount(P.first->Size); + return Num; +} + +size_t MipsGotSection::FileGot::getIndexEntriesNum() 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 == size_t(-1)) { + Gots.emplace_back(); + Gots.back().File = &F; + F.MipsGotIndex = Gots.size() - 1; + } + return Gots[F.MipsGotIndex]; +} + +uint64_t MipsGotSection::getPageEntryOffset(const InputFile &F, + const SymbolBody &B, int64_t Addend) const { + const FileGot &G = Gots[F.MipsGotIndex]; const OutputSection *OutSec = cast(&B)->Section->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 Index = G.PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff; + return Index * Config->Wordsize; } -uint64_t MipsGotSection::getBodyEntryOffset(const SymbolBody &B, +uint64_t MipsGotSection::getBodyEntryOffset(const InputFile &F, + const SymbolBody &B, 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; + const FileGot &G = Gots[F.MipsGotIndex]; + SymbolBody *Body = const_cast(&B); + if (B.isTls()) { + auto E = G.Tls.find(Body); + assert(E != G.Tls.end()); + return E->second * Config->Wordsize; } - return Index * Config->Wordsize; + if (B.isPreemptible()) { + auto E = G.Global.find(Body); + assert(E != G.Global.end()); + return E->second * Config->Wordsize; + } + auto E = G.Local16.find({Body, Addend}); + assert(E != G.Local16.end()); + return E->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]; + auto E = G.DynTlsSymbols.find(nullptr); + assert(E != G.DynTlsSymbols.end()); + return E->second * Config->Wordsize; } -uint64_t MipsGotSection::getGlobalDynOffset(const SymbolBody &B) const { - return B.GlobalDynIndex * Config->Wordsize; +uint64_t MipsGotSection::getGlobalDynOffset(const InputFile &F, + const SymbolBody &B) const { + const FileGot &G = Gots[F.MipsGotIndex]; + auto E = G.DynTlsSymbols.find(const_cast(&B)); + assert(E != G.DynTlsSymbols.end()); + return E->second * Config->Wordsize; } const SymbolBody *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.PageIndexMap, Src.PageIndexMap); + 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) + Tmp.getIndexEntriesNum(); + if (Count * Config->Wordsize > Config->MipsGotSize) + return false; -void MipsGotSection::finalizeContents() { - updateAllocSize(); + std::swap(Tmp, Dst); + return true; } +void MipsGotSection::finalizeContents() { updateAllocSize(); } + void 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 = HeaderEntriesNum * Config->Wordsize; + for (const FileGot &G : Gots) + Size += G.getEntriesNum() * Config->Wordsize; +} + +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(); + } + + // 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.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 = Index; + Index += getMipsPageCount(P.first->Size); + } + 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 SymbolBody::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) { + uint64_t Offset = P.second * Config->Wordsize; + if (P.first->isPreemptible()) + In::RelaDyn->addReloc( + {Target->TlsGotRel, this, Offset, false, P.first, 0}); + } + for (std::pair &P : Got.DynTlsSymbols) { + uint64_t Offset = P.second * Config->Wordsize; + if (P.first == nullptr) { + if (!Config->Pic) + continue; + In::RelaDyn->addReloc( + {Target->TlsModuleIndexRel, this, Offset, false, nullptr, 0}); + } else { + if (!P.first->isPreemptible()) + continue; + In::RelaDyn->addReloc( + {Target->TlsModuleIndexRel, this, Offset, false, P.first, 0}); + Offset += Config->Wordsize; + In::RelaDyn->addReloc( + {Target->TlsOffsetRel, this, Offset, false, P.first, 0}); + } + } + + // 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; + In::RelaDyn->addReloc( + {Target->RelativeRel, this, Offset, false, P.first, 0}); + } + if (!Config->Pic) + continue; + // Dynamic relocations for "local" entries in case of PIC. + for (const std::pair &L : Got.PageIndexMap) { + size_t PageCount = getMipsPageCount(L.first->Size); + for (size_t PI = 0; PI < PageCount; ++PI) { + uint64_t Offset = (L.second + PI) * Config->Wordsize; + In::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; + In::RelaDyn->addReloc({Target->RelativeRel, this, Offset, true, + P.first.first, P.first.second}); + } } - Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) * - Config->Wordsize; } bool MipsGotSection::empty() const { @@ -839,8 +981,11 @@ return Config->Relocatable; } -uint64_t MipsGotSection::getGp() const { - return ElfSym::MipsGp->getVA(0); +uint64_t MipsGotSection::getGp(const InputFile *F) const { + if (!F || F->MipsGotIndex == 0 || F->MipsGotIndex == size_t(-1)) + return ElfSym::MipsGp->getVA(0); + return this->getVA() + Gots[F->MipsGotIndex].StartIndex * Config->Wordsize + + 0x7ff0; } static uint64_t readUint(uint8_t *Buf) { @@ -872,47 +1017,53 @@ // 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); + for (const FileGot &G : Gots) { + // Write 'page address' entries to the local part of the GOT. + for (const std::pair &L : G.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 *Addr = Buf + (L.second + PI) * Config->Wordsize; + writeUint(Addr, FirstPageAddr + PI * 0x10000); + } } - } - Buf += PageEntriesNum * Config->Wordsize; - auto AddEntry = [&](const GotEntry &SA) { - uint8_t *Entry = Buf; - Buf += Config->Wordsize; - const SymbolBody *Body = SA.first; - uint64_t VA = Body->getVA(SA.second); - 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 SymbolBody *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); + // 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) { + uint8_t *Addr = Buf + P.second * Config->Wordsize; + writeUint(Addr, P.first.first->getVA(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) { + uint8_t *Addr = Buf + P.second * Config->Wordsize; + writeUint(Addr, P.first->getVA(0)); + } + } + for (const std::pair &P : G.Relocs) { + uint8_t *Addr = Buf + P.second * Config->Wordsize; + writeUint(Addr, P.first->getVA(0)); } - if (B->GlobalDynIndex != -1U) { - uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize; - writeUint(Entry, 1); - Entry += Config->Wordsize; - writeUint(Entry, VA - 0x8000); + for (const std::pair &P : G.Tls) { + uint8_t *Addr = Buf + P.second * Config->Wordsize; + uint64_t VA = P.first->getVA(); + writeUint(Addr, P.first->isPreemptible() ? VA : VA - 0x7000); + } + for (const std::pair &P : G.DynTlsSymbols) { + if (P.first == nullptr) { + if (!Config->Pic) + writeUint(Buf + P.second * Config->Wordsize, 1); + } else { + if (!P.first->isPreemptible()) { + uint8_t *Addr = Buf + P.second * Config->Wordsize; + writeUint(Addr, 1); + writeUint(Addr + Config->Wordsize, P.first->getVA() - 0x8000); + } + } } } } @@ -1182,7 +1333,10 @@ int64_t DynamicReloc::getAddend() 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 { @@ -1225,11 +1379,6 @@ if (Config->IsRela) P->r_addend = Rel.getAddend(); P->r_offset = Rel.getOffset(); - if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot) - // Dynamic relocation against MIPS GOT section make deal TLS entries - // allocated in the end of the GOT. We need to adjust the offset to take - // in account 'local' and 'global' GOT entries. - P->r_offset += InX::MipsGot->getTlsOffset(); P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); } @@ -1272,10 +1421,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.Symbol->IsInGlobalMipsGot; - bool RIsInLocalGot = !R.Symbol->IsInGlobalMipsGot; - if (LIsInLocalGot || RIsInLocalGot) - return !RIsInLocalGot; + if (!L.Symbol->isInGot() || !R.Symbol->isInGot()) + return !L.Symbol->isInGot(); return L.Symbol->GotIndex < R.Symbol->GotIndex; } @@ -2239,6 +2386,11 @@ StringTableSection *InX::StrTab; SymbolTableBaseSection *InX::SymTab; +template void MipsGotSection::build(); +template void MipsGotSection::build(); +template void MipsGotSection::build(); +template void MipsGotSection::build(); + template void PltSection::addEntry(SymbolBody &Sym); template void PltSection::addEntry(SymbolBody &Sym); template void PltSection::addEntry(SymbolBody &Sym); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1195,6 +1195,9 @@ if (ErrorCount) return; + if (In::MipsGot) + In::MipsGot->template build(); + // So far we have added sections from input object files. // This function adds linker-created Out::* sections. addPredefinedSections(); @@ -1665,8 +1668,6 @@ if (ElfSym::Bss) ElfSym::Bss->Section = findSection(".bss"); - // Setup MIPS _gp_disp/__gnu_local_gp symbols which should - // be equal to the _gp symbol's value. if (Config->EMachine == EM_MIPS) { if (!ElfSym::MipsGp->Value) { // Find GP-relative section with the lowest address 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 @@ -77,8 +77,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-and-copy.s =================================================================== --- test/ELF/mips-got-and-copy.s +++ test/ELF/mips-got-and-copy.s @@ -14,8 +14,8 @@ # CHECK: Relocations [ # CHECK-NEXT: Section (7) .rel.dyn { -# CHECK-NEXT: 0x[[DATA0:[0-9A-F]+]] R_MIPS_COPY data0 # CHECK-NEXT: 0x[[DATA1:[0-9A-F]+]] R_MIPS_COPY data1 +# CHECK-NEXT: 0x[[DATA0:[0-9A-F]+]] R_MIPS_COPY data0 # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: Primary GOT { @@ -28,18 +28,14 @@ # CHECK-NEXT: Access: -32744 # CHECK-NEXT: Initial: 0x[[DATA0]] # CHECK-NEXT: } -# CHECK-NEXT: ] -# CHECK-NEXT: Global entries [ # CHECK-NEXT: Entry { # CHECK-NEXT: Address: # CHECK-NEXT: Access: -32740 # CHECK-NEXT: Initial: 0x[[DATA1]] -# CHECK-NEXT: Value: 0x[[DATA1]] -# CHECK-NEXT: Type: Object -# CHECK-NEXT: Section: .bss -# CHECK-NEXT: Name: data1@ # CHECK-NEXT: } # CHECK-NEXT: ] +# CHECK-NEXT: Global entries [ +# CHECK-NEXT: ] # CHECK-NEXT: Number of TLS and multi-GOT entries: 0 # CHECK-NEXT: } 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) .rela.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) .rela.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