Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -251,6 +251,10 @@ Symtab.addIgnoredSym("_GLOBAL_OFFSET_TABLE_"); } + // Add target specific symbols + if (Config->EMachine == EM_MIPS) + Symtab.addAbsoluteSym("_gp", 0); + for (std::unique_ptr &F : Files) Symtab.addFile(std::move(F)); Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -109,9 +109,7 @@ public: GotSection(); - void finalize() override { - this->Header.sh_size = Entries.size() * sizeof(uintX_t); - } + void finalize() override; void writeTo(uint8_t *Buf) override; void addEntry(SymbolBody *Sym); bool empty() const { return Entries.empty(); } Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -76,7 +76,7 @@ } template void GotSection::addEntry(SymbolBody *Sym) { - Sym->GotIndex = Entries.size(); + Sym->GotIndex = Target->getGotHeaderEntriesNum() + Entries.size(); Entries.push_back(Sym); } @@ -86,7 +86,14 @@ return this->getVA() + B.GotIndex * sizeof(uintX_t); } +template void GotSection::finalize() { + this->Header.sh_size = + (Target->getGotHeaderEntriesNum() + Entries.size()) * sizeof(uintX_t); +} + template void GotSection::writeTo(uint8_t *Buf) { + Target->writeGotHeaderEntries(Buf); + Buf += Target->getGotHeaderEntriesNum() * sizeof(uintX_t); for (const SymbolBody *B : Entries) { uint8_t *Entry = Buf; Buf += sizeof(uintX_t); @@ -640,6 +647,7 @@ return D.Section.getVA() + D.Sym.st_value; } case SymbolBody::DefinedAbsoluteKind: + case SymbolBody::DefinedAbsoluteSyntheticKind: return cast>(S).Sym.st_value; case SymbolBody::DefinedRegularKind: { const auto &DR = cast>(S); @@ -1011,6 +1019,7 @@ } case SymbolBody::UndefinedKind: case SymbolBody::DefinedAbsoluteKind: + case SymbolBody::DefinedAbsoluteSyntheticKind: case SymbolBody::LazyKind: break; } Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -50,6 +50,8 @@ SymbolBody *addUndefined(StringRef Name); SymbolBody *addUndefinedOpt(StringRef Name); + void addAbsoluteSym(StringRef Name, + typename llvm::object::ELFFile::uintX_t Value); void addSyntheticSym(StringRef Name, OutputSectionBase &Section, typename llvm::object::ELFFile::uintX_t Value); void addIgnoredSym(StringRef Name); Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -71,6 +71,12 @@ } template +void SymbolTable::addAbsoluteSym(StringRef Name, + typename ELFFile::uintX_t Value) { + resolve(new (Alloc) DefinedAbsoluteSynthetic(Name, Value)); +} + +template void SymbolTable::addSyntheticSym(StringRef Name, OutputSectionBase &Section, typename ELFFile::uintX_t Value) { Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -59,6 +59,7 @@ DefinedFirst, DefinedRegularKind = DefinedFirst, DefinedAbsoluteKind, + DefinedAbsoluteSyntheticKind, DefinedCommonKind, DefinedSyntheticKind, SharedKind, @@ -174,6 +175,11 @@ typedef ELFSymbolBody Base; typedef typename Base::Elf_Sym Elf_Sym; +protected: + typedef typename Base::Kind Kind; + DefinedAbsolute(Kind K, StringRef N, const Elf_Sym &Sym) + : Defined(K, N, Sym) {} + public: static Elf_Sym IgnoreUndef; @@ -181,13 +187,38 @@ : Defined(Base::DefinedAbsoluteKind, N, Sym) {} static bool classof(const SymbolBody *S) { - return S->kind() == Base::DefinedAbsoluteKind; + Kind K = S->kind(); + return K == Base::DefinedAbsoluteKind || + K == Base::DefinedAbsoluteSyntheticKind; } }; template typename DefinedAbsolute::Elf_Sym DefinedAbsolute::IgnoreUndef; +template +class DefinedAbsoluteSynthetic : public DefinedAbsolute { + typedef ELFSymbolBody Base; + typedef typename Base::Elf_Sym Elf_Sym; + +public: + typedef typename llvm::object::ELFFile::uintX_t uintX_t; + DefinedAbsoluteSynthetic(StringRef N, uintX_t Addr) + : DefinedAbsolute(Base::DefinedAbsoluteSyntheticKind, N, Sym) { + memset(&Sym, 0, sizeof(Sym)); + Sym.st_value = Addr; + } + + void setValue(uintX_t Value) { Sym.st_value = Value; } + + static bool classof(const SymbolBody *S) { + return S->kind() == Base::DefinedAbsoluteSyntheticKind; + } + +private: + Elf_Sym Sym; +}; + template class DefinedCommon : public Defined { typedef ELFSymbolBody Base; typedef typename Base::Elf_Sym Elf_Sym; Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -11,6 +11,7 @@ #define LLD_ELF_TARGET_H #include "llvm/ADT/StringRef.h" +#include "llvm/Object/ELF.h" #include @@ -31,7 +32,9 @@ unsigned getPltZeroEntrySize() const { return PltZeroEntrySize; } unsigned getPltEntrySize() const { return PltEntrySize; } bool supportsLazyRelocations() const { return LazyRelocations; } + unsigned getGotHeaderEntriesNum() const { return GotHeaderEntriesNum; } virtual unsigned getPLTRefReloc(unsigned Type) const; + virtual void writeGotHeaderEntries(uint8_t *Buf) const; virtual void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const = 0; virtual void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr) const = 0; @@ -66,11 +69,15 @@ unsigned RelativeReloc; unsigned PltEntrySize = 8; unsigned PltZeroEntrySize = 0; + unsigned GotHeaderEntriesNum = 0; bool LazyRelocations = false; }; uint64_t getPPC64TocBase(); +template +typename llvm::object::ELFFile::uintX_t getMipsGpAddr(); + extern std::unique_ptr Target; TargetInfo *createTarget(); } Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -35,6 +35,14 @@ std::unique_ptr Target; +template static uint32_t read32(const uint8_t *L); +template <> uint32_t read32(const uint8_t *L) { return read32le(L); } +template <> uint32_t read32(const uint8_t *L) { return read32be(L); } + +template static void write32(uint8_t *L, uint32_t V); +template <> void write32(uint8_t *L, uint32_t V) { write32le(L, V); } +template <> void write32(uint8_t *L, uint32_t V) { write32be(L, V); } + static void add32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) + V); } static void add32be(uint8_t *L, int32_t V) { write32be(L, read32be(L) + V); } static void or32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) | V); } @@ -108,6 +116,7 @@ template class MipsTargetInfo final : public TargetInfo { public: MipsTargetInfo(); + void writeGotHeaderEntries(uint8_t *Buf) const override; void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr) const override; @@ -155,6 +164,8 @@ bool TargetInfo::isRelRelative(uint32_t Type) const { return true; } +void TargetInfo::writeGotHeaderEntries(uint8_t *Buf) const {} + X86TargetInfo::X86TargetInfo() { PCRelReloc = R_386_PC32; GotReloc = R_386_GLOB_DAT; @@ -663,6 +674,16 @@ template MipsTargetInfo::MipsTargetInfo() { PageSize = 65536; + GotRefReloc = R_MIPS_GOT16; + GotHeaderEntriesNum = 2; +} + +template +void MipsTargetInfo::writeGotHeaderEntries(uint8_t *Buf) const { + typedef typename llvm::object::ELFFile::Elf_Off Elf_Off; + auto *P = reinterpret_cast(Buf); + // Module pointer + P[1] = ELFT::Is64Bits ? 0x8000000000000000 : 0x80000000; } template @@ -677,7 +698,7 @@ template bool MipsTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { - return false; + return Type == R_MIPS_GOT16; } template @@ -695,9 +716,27 @@ case R_MIPS_32: add32(Loc, SA); break; + case R_MIPS_GOT16: { + int64_t V = SA - getMipsGpAddr(); + if (!isInt<16>(V)) + error("Relocation R_MIPS_GOT16 out of range"); + write32(Loc, (read32(Loc) & 0xffff0000) | (V & 0xffff)); + break; + } default: error("unrecognized reloc " + Twine(Type)); } } + +template +typename llvm::object::ELFFile::uintX_t getMipsGpAddr() { + const unsigned GPOffset = 0x7ff0; + return Out::Got->empty() ? 0 : (Out::Got->getVA() + GPOffset); +} + +template uint32_t getMipsGpAddr(); +template uint32_t getMipsGpAddr(); +template uint64_t getMipsGpAddr(); +template uint64_t getMipsGpAddr(); } } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -644,6 +644,11 @@ return Ret; } +template static void updateMipsGpSymbol(SymbolTable &S) { + if (auto *B = dyn_cast_or_null>(S.find("_gp"))) + B->setValue(getMipsGpAddr()); +} + // Visits all sections to create PHDRs and to assign incremental, // non-overlapping addresses to output sections. template void Writer::assignAddresses() { @@ -743,6 +748,10 @@ // Add space for section headers. SectionHeaderOff = RoundUpToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4); FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr); + + // Update target specific symbols + if (Config->EMachine == EM_MIPS) + updateMipsGpSymbol(Symtab); } // Returns the number of PHDR entries. Index: test/elf2/basic-mips.s =================================================================== --- test/elf2/basic-mips.s +++ test/elf2/basic-mips.s @@ -27,7 +27,7 @@ # CHECK-NEXT: Version: 1 # CHECK-NEXT: Entry: 0x20000 # CHECK-NEXT: ProgramHeaderOffset: 0x34 -# CHECK-NEXT: SectionHeaderOffset: 0x10080 +# CHECK-NEXT: SectionHeaderOffset: 0x10094 # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: HeaderSize: 52 @@ -138,7 +138,7 @@ # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 # CHECK-NEXT: Offset: 0x10010 -# CHECK-NEXT: Size: 32 +# CHECK-NEXT: Size: 48 # CHECK-NEXT: Link: 8 # CHECK-NEXT: Info: 1 # CHECK-NEXT: AddressAlignment: 4 @@ -151,7 +151,7 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x10030 +# CHECK-NEXT: Offset: 0x10040 # CHECK-NEXT: Size: 68 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -165,8 +165,8 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x10074 -# CHECK-NEXT: Size: 9 +# CHECK-NEXT: Offset: 0x10084 +# CHECK-NEXT: Size: 13 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 1 @@ -184,6 +184,15 @@ # CHECK-NEXT: Section: Undefined (0x0) # CHECK-NEXT: } # CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _gp +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local (0x0) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute (0xFFF1) +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { # CHECK-NEXT: Name: __start # CHECK-NEXT: Value: 0x20000 # CHECK-NEXT: Size: 0 Index: test/elf2/emulation.s =================================================================== --- test/elf2/emulation.s +++ test/elf2/emulation.s @@ -111,7 +111,7 @@ # MIPS-NEXT: Version: 1 # MIPS-NEXT: Entry: 0x100B0 # MIPS-NEXT: ProgramHeaderOffset: 0x34 -# MIPS-NEXT: SectionHeaderOffset: 0x11C +# MIPS-NEXT: SectionHeaderOffset: 0x130 # MIPS-NEXT: Flags [ (0x0) # MIPS-NEXT: ] @@ -137,7 +137,7 @@ # MIPSEL-NEXT: Version: 1 # MIPSEL-NEXT: Entry: 0x100B0 # MIPSEL-NEXT: ProgramHeaderOffset: 0x34 -# MIPSEL-NEXT: SectionHeaderOffset: 0x11C +# MIPSEL-NEXT: SectionHeaderOffset: 0x130 # MIPSEL-NEXT: Flags [ (0x0) # MIPSEL-NEXT: ] Index: test/elf2/mips-got-relocs.s =================================================================== --- /dev/null +++ test/elf2/mips-got-relocs.s @@ -0,0 +1,50 @@ +# Check R_MIPS_GOT16 relocation calculation. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o +# RUN: ld.lld2 %t-be.o -o %t-be.exe +# RUN: llvm-objdump -section-headers -t %t-be.exe | FileCheck %s +# RUN: llvm-objdump -s -section=.got %t-be.exe | FileCheck -check-prefix=BEGOT %s +# RUN: llvm-objdump -d %t-be.exe | FileCheck -check-prefix=BEDIS %s + +# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o +# RUN: ld.lld2 %t-el.o -o %t-el.exe +# RUN: llvm-objdump -section-headers -t %t-el.exe | FileCheck %s +# RUN: llvm-objdump -s -section=.got %t-el.exe | FileCheck -check-prefix=ELGOT %s +# RUN: llvm-objdump -d %t-el.exe | FileCheck -check-prefix=ELDIS %s + +# REQUIRES: mips + + .text + .globl __start +__start: + lui $2, %got(v1) + + .data + .globl v1 + .type v1,@object + .size v1,4 +v1: + .word 0 + +# CHECK: Sections: +# CHECK: .got 0000000c 0000000000030004 DATA +# CHECK: SYMBOL TABLE: +# CHECK: 00037ff4 *ABS* 00000000 _gp +# ^-- .got + GP offset (0x7ff0) +# CHECK: 00030000 g .data 00000004 v1 + +# BEGOT: Contents of section .got: +# BEGOT: 30004 00000000 80000000 00030000 +# ^ ^ ^-- v1 (0x30000) +# | +-- Module pointer (0x80000000) +# +-- Lazy resolver (0x0) + +# ELGOT: Contents of section .got: +# ELGOT: 30004 00000000 00000080 00000300 +# ^ ^ ^-- v1 (0x30000) +# | +-- Module pointer (0x80000000) +# +-- Lazy resolver (0x0) + +# v1GotAddr(0x3000c) - _gp (0x37ff4) = -0x7fe8 => 0x8018 = 32792 +# BEDIS: 20000: 3c 02 80 18 lui $2, 32792 +# ELDIS: 20000: 18 80 02 3c lui $2, 32792