Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -223,7 +223,7 @@ } template void LinkerDriver::link(opt::InputArgList &Args) { - SymbolTable Symtab; + SymbolTable &Symtab = SymbolTable::getInstance(); Target.reset(createTarget()); if (!Config->Shared) { @@ -251,6 +251,8 @@ Symtab.addIgnoredSym("_GLOBAL_OFFSET_TABLE_"); } + Target->addSpecificSymbols(); + for (std::unique_ptr &F : Files) Symtab.addFile(std::move(F)); Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -110,9 +110,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 @@ -83,10 +83,18 @@ template typename GotSection::uintX_t GotSection::getEntryAddr(const SymbolBody &B) const { - return this->getVA() + B.GotIndex * sizeof(uintX_t); + return this->getVA() + Target->getGotFirstElementSize() + + B.GotIndex * sizeof(uintX_t); +} + +template void GotSection::finalize() { + this->Header.sh_size = + Target->getGotFirstElementSize() + Entries.size() * sizeof(uintX_t); } template void GotSection::writeTo(uint8_t *Buf) { + Target->writeGotFirstElement(Buf); + Buf += Target->getGotFirstElementSize(); for (const SymbolBody *B : Entries) { uint8_t *Entry = Buf; Buf += sizeof(uintX_t); Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -30,7 +30,7 @@ // to replace the lazy symbol. The logic is implemented in resolve(). template class SymbolTable { public: - SymbolTable(); + static SymbolTable &getInstance(); void addFile(std::unique_ptr File); @@ -50,6 +50,9 @@ SymbolBody *addUndefined(StringRef Name); SymbolBody *addUndefinedOpt(StringRef Name); + void + addAbsoluteSym(StringRef Name, + const typename llvm::object::ELFFile::Elf_Sym &ESym); void addSyntheticSym(StringRef Name, OutputSectionBase &Section, typename llvm::object::ELFFile::uintX_t Value); void addIgnoredSym(StringRef Name); @@ -58,6 +61,7 @@ SymbolBody *find(StringRef Name); private: + SymbolTable(); Symbol *insert(SymbolBody *New); void addELFFile(ELFFileBase *File); void addLazy(Lazy *New); Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -26,6 +26,11 @@ using namespace lld; using namespace lld::elf2; +template SymbolTable &SymbolTable::getInstance() { + static SymbolTable Instance; + return Instance; +} + template SymbolTable::SymbolTable() {} template bool SymbolTable::shouldUseRela() const { @@ -71,6 +76,13 @@ } template +void SymbolTable::addAbsoluteSym( + StringRef Name, const typename ELFFile::Elf_Sym &ESym) { + auto Sym = new (Alloc) DefinedAbsolute(Name, ESym); + resolve(Sym); +} + +template void SymbolTable::addSyntheticSym(StringRef Name, OutputSectionBase &Section, typename ELFFile::uintX_t Value) { Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -31,7 +31,9 @@ unsigned getPltZeroEntrySize() const { return PltZeroEntrySize; } unsigned getPltEntrySize() const { return PltEntrySize; } bool supportsLazyRelocations() const { return LazyRelocations; } + unsigned getGotFirstElementSize() const { return GotFirstElementSize; } virtual unsigned getPLTRefReloc(unsigned Type) const; + virtual void writeGotFirstElement(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; @@ -44,6 +46,8 @@ virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const = 0; virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA) const = 0; + virtual void addSpecificSymbols() const; + virtual void updateSpecificSymbols() const; virtual ~TargetInfo(); @@ -66,6 +70,7 @@ unsigned RelativeReloc; unsigned PltEntrySize = 8; unsigned PltZeroEntrySize = 0; + unsigned GotFirstElementSize = 0; bool LazyRelocations = false; }; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -19,6 +19,7 @@ #include "Error.h" #include "OutputSections.h" #include "Symbols.h" +#include "SymbolTable.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Object/ELF.h" @@ -43,6 +44,14 @@ template <> void add32(uint8_t *L, int32_t V) { add32le(L, V); } template <> void add32(uint8_t *L, int32_t V) { add32be(L, V); } +template static void update32Lo16(uint8_t *L, uint16_t V); +template <> void update32Lo16(uint8_t *L, uint16_t V) { + write32le(L, (read32le(L) & 0xffff0000) | V); +} +template <> void update32Lo16(uint8_t *L, uint16_t V) { + write32be(L, (read32be(L) & 0xffff0000) | V); +} + namespace { class X86TargetInfo final : public TargetInfo { public: @@ -106,8 +115,11 @@ }; template class MipsTargetInfo final : public TargetInfo { + typedef typename llvm::object::ELFFile::uintX_t uintX_t; + public: MipsTargetInfo(); + void writeGotFirstElement(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; @@ -117,6 +129,14 @@ bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA) const override; + void addSpecificSymbols() const override; + void updateSpecificSymbols() const override; + +private: + static const uint8_t GotFirstElementRawData[]; + mutable typename llvm::object::ELFFile::Elf_Sym GpSym; + + static uintX_t getGpAddr(); }; } // anonymous namespace @@ -155,6 +175,11 @@ bool TargetInfo::isRelRelative(uint32_t Type) const { return true; } +void TargetInfo::writeGotFirstElement(uint8_t *Buf) const {} + +void TargetInfo::addSpecificSymbols() const {} +void TargetInfo::updateSpecificSymbols() const {} + X86TargetInfo::X86TargetInfo() { PCRelReloc = R_386_PC32; GotReloc = R_386_GLOB_DAT; @@ -671,8 +696,23 @@ } } +template <> +const uint8_t MipsTargetInfo::GotFirstElementRawData[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}; + +template <> +const uint8_t MipsTargetInfo::GotFirstElementRawData[] = { + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00}; + template MipsTargetInfo::MipsTargetInfo() { PageSize = 65536; + GotFirstElementSize = sizeof(GotFirstElementRawData); + memset(&GpSym, 0, sizeof(GpSym)); +} + +template +void MipsTargetInfo::writeGotFirstElement(uint8_t *Buf) const { + memcpy(Buf, GotFirstElementRawData, sizeof(GotFirstElementRawData)); } template @@ -687,7 +727,7 @@ template bool MipsTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { - return false; + return Type == R_MIPS_GOT16; } template @@ -705,9 +745,30 @@ case R_MIPS_32: add32(Loc, SA); break; + case R_MIPS_GOT16: { + int64_t V = SA - getGpAddr(); + if (!isInt<16>(V)) + error("Relocation R_MIPS_GOT16 out of range"); + update32Lo16(Loc, V); + break; + } default: error("unrecognized reloc " + Twine(Type)); } } + +template void MipsTargetInfo::addSpecificSymbols() const { + SymbolTable &Symtab = SymbolTable::getInstance(); + Symtab.addAbsoluteSym("_gp", GpSym); +} + +template void MipsTargetInfo::updateSpecificSymbols() const { + GpSym.st_value = getGpAddr(); +} + +template +typename MipsTargetInfo::uintX_t MipsTargetInfo::getGpAddr() { + return Out::Got->empty() ? 0 : (Out::Got->getVA() + 0x7ff0); +} } } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -133,6 +133,7 @@ copyLocalSymbols(); createSections(); assignAddresses(); + Target->updateSpecificSymbols(); openFile(Config->OutputFile); writeHeader(); writeSections(); 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.mips %t-be.o -o %t-be.exe -m elf32btsmip +# RUN: llvm-objdump -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.mips %t-el.o -o %t-el.exe -m elf32ltsmip +# RUN: llvm-objdump -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: SYMBOL TABLE: +# CHECK: 004100e0 l d .got 00000000 .got +# CHECK: 004180d0 *ABS* 00000000 _gp +# ^-- .got + GP offset (0x7ff0) +# CHECK: 004100d0 g .data 00000004 v1 + +# BEGOT: Contents of section .got: +# BEGOT: 4100e0 00000000 80000000 004100d0 +# ^ ^ ^-- v1 (0x4100d0) +# | +-- Module pointer (0x80000000) +# +-- Lazy resolver (0x0) + +# ELGOT: Contents of section .got: +# ELGOT: 4100e0 00000000 00000080 d0004100 +# ^ ^ ^-- v1 (0x4100d0) +# | +-- Module pointer (0x80000000) +# +-- Lazy resolver (0x0) + + +# GotAddr of v1 (0x4100e8) - _gp (0x4180d0) = -0x7fe8 => 0x8018 = 32792 +# BEDIS: 4000b0: 3c 02 80 18 lui $2, 32792 +# ELDIS: 4000b0: 18 80 02 3c lui $2, 32792