Index: lld/trunk/ELF/OutputSections.h =================================================================== --- lld/trunk/ELF/OutputSections.h +++ lld/trunk/ELF/OutputSections.h @@ -122,6 +122,16 @@ bool empty() const { return Entries.empty(); } uintX_t getEntryAddr(const SymbolBody &B) 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 + // table properties. + // Returns nullptr if the global part is empty. + const SymbolBody *getMipsFirstGlobalEntry() const; + + // Returns the number of entries in the local part of GOT including + // the number of reserved entries. This method is MIPS-specific. + unsigned getMipsLocalEntriesNum() const; + private: std::vector Entries; }; @@ -403,6 +413,7 @@ static HashTableSection *HashTab; static InterpSection *Interp; static OutputSection *Bss; + static OutputSection *MipsRldMap; static OutputSectionBase *Opd; static uint8_t *OpdBuf; static PltSection *Plt; @@ -424,6 +435,7 @@ template HashTableSection *Out::HashTab; template InterpSection *Out::Interp; template OutputSection *Out::Bss; +template OutputSection *Out::MipsRldMap; template OutputSectionBase *Out::Opd; template uint8_t *Out::OpdBuf; template PltSection *Out::Plt; Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -94,6 +94,17 @@ return this->getVA() + B.GotIndex * sizeof(uintX_t); } +template +const SymbolBody *GotSection::getMipsFirstGlobalEntry() const { + return Entries.empty() ? nullptr : Entries.front(); +} + +template +unsigned GotSection::getMipsLocalEntriesNum() const { + // TODO: Update when the suppoort of GOT entries for local symbols is added. + return Target->getGotHeaderEntriesNum(); +} + template void GotSection::finalize() { this->Header.sh_size = (Target->getGotHeaderEntriesNum() + Entries.size()) * sizeof(uintX_t); @@ -477,6 +488,12 @@ Elf_Shdr &Header = this->Header; Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; Header.sh_entsize = ELFT::Is64Bits ? 16 : 8; + + // .dynamic section is not writable on MIPS. + // See "Special Section" in Chapter 4 in the following document: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (Config->EMachine == EM_MIPS) + Header.sh_flags = llvm::ELF::SHF_ALLOC; } template void DynamicSection::finalize() { @@ -495,7 +512,7 @@ if (Out::RelaPlt && Out::RelaPlt->hasRelocs()) { ++NumEntries; // DT_JMPREL ++NumEntries; // DT_PLTRELSZ - ++NumEntries; // DT_PLTGOT + ++NumEntries; // DT_PLTGOT / DT_MIPS_PLTGOT ++NumEntries; // DT_PLTREL } @@ -558,6 +575,19 @@ ++NumEntries; // DT_FLAGS if (DtFlags1) ++NumEntries; // DT_FLAGS_1 + + if (Config->EMachine == EM_MIPS) { + ++NumEntries; // DT_MIPS_RLD_VERSION + ++NumEntries; // DT_MIPS_FLAGS + ++NumEntries; // DT_MIPS_BASE_ADDRESS + ++NumEntries; // DT_MIPS_SYMTABNO + ++NumEntries; // DT_MIPS_LOCAL_GOTNO + ++NumEntries; // DT_MIPS_GOTSYM; + ++NumEntries; // DT_PLTGOT + if (Out::MipsRldMap) + ++NumEntries; // DT_MIPS_RLD_MAP + } + ++NumEntries; // DT_NULL Header.sh_size = NumEntries * Header.sh_entsize; @@ -588,7 +618,12 @@ if (Out::RelaPlt && Out::RelaPlt->hasRelocs()) { WritePtr(DT_JMPREL, Out::RelaPlt->getVA()); WriteVal(DT_PLTRELSZ, Out::RelaPlt->getSize()); - WritePtr(DT_PLTGOT, Out::GotPlt->getVA()); + // On MIPS, the address of the .got.plt section is stored in + // the DT_MIPS_PLTGOT entry because the DT_PLTGOT entry points to + // the .got section. See "Dynamic Section" in the following document: + // https://sourceware.org/ml/binutils/2008-07/txt00000.txt + WritePtr((Config->EMachine == EM_MIPS) ? DT_MIPS_PLTGOT : DT_PLTGOT, + Out::GotPlt->getVA()); WriteVal(DT_PLTREL, Out::RelaPlt->isRela() ? DT_RELA : DT_REL); } @@ -640,6 +675,25 @@ WriteVal(DT_FLAGS, DtFlags); if (DtFlags1) WriteVal(DT_FLAGS_1, DtFlags1); + + // See "Dynamic Section" in Chapter 5 in the following document + // for detailed description: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (Config->EMachine == EM_MIPS) { + WriteVal(DT_MIPS_RLD_VERSION, 1); + WriteVal(DT_MIPS_FLAGS, RHF_NOTPOT); + WritePtr(DT_MIPS_BASE_ADDRESS, Target->getVAStart()); + WriteVal(DT_MIPS_SYMTABNO, Out::DynSymTab->getNumSymbols()); + WriteVal(DT_MIPS_LOCAL_GOTNO, Out::Got->getMipsLocalEntriesNum()); + if (const SymbolBody *B = Out::Got->getMipsFirstGlobalEntry()) + WriteVal(DT_MIPS_GOTSYM, B->getDynamicSymbolTableIndex()); + else + WriteVal(DT_MIPS_GOTSYM, Out::DynSymTab->getNumSymbols()); + WritePtr(DT_PLTGOT, Out::Got->getVA()); + if (Out::MipsRldMap) + WritePtr(DT_MIPS_RLD_MAP, Out::MipsRldMap->getVA()); + } + WriteVal(DT_NULL, 0); } Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -632,8 +632,23 @@ OutputSections.push_back(Out::RelaDyn); if (Out::RelaPlt && Out::RelaPlt->hasRelocs()) OutputSections.push_back(Out::RelaPlt); + // This is a MIPS specific section to hold a space within the data segment + // of executable file which is pointed to by the DT_MIPS_RLD_MAP entry. + // See "Dynamic section" in Chapter 5 in the following document: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (Config->EMachine == EM_MIPS && !Config->Shared) { + Out::MipsRldMap = new (SecAlloc.Allocate()) + OutputSection(".rld_map", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + Out::MipsRldMap->setSize(ELFT::Is64Bits ? 8 : 4); + Out::MipsRldMap->updateAlign(ELFT::Is64Bits ? 8 : 4); + OutputSections.push_back(Out::MipsRldMap); + } } - if (!Out::Got->empty()) + + // We add the .got section to the result for dynamic MIPS target because + // its address and properties are mentioned in the .dynamic section. + if (!Out::Got->empty() || + (isOutputDynamic() && Config->EMachine == EM_MIPS)) OutputSections.push_back(Out::Got); if (Out::GotPlt && !Out::GotPlt->empty()) OutputSections.push_back(Out::GotPlt); Index: lld/trunk/test/elf2/Inputs/mips-dynamic.s =================================================================== --- lld/trunk/test/elf2/Inputs/mips-dynamic.s +++ lld/trunk/test/elf2/Inputs/mips-dynamic.s @@ -0,0 +1,4 @@ + .text + .globl _foo +_foo: + nop Index: lld/trunk/test/elf2/mips-dynamic.s =================================================================== --- lld/trunk/test/elf2/mips-dynamic.s +++ lld/trunk/test/elf2/mips-dynamic.s @@ -0,0 +1,91 @@ +# Check MIPS specific .dynamic section entries. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %p/Inputs/mips-dynamic.s -o %td.o +# RUN: ld.lld2 -shared %td.o -o %td.so + +# RUN: ld.lld2 %t.o %td.so -o %t.exe +# RUN: llvm-readobj -sections -dynamic-table %t.exe \ +# RUN: | FileCheck -check-prefix=EXE %s + +# RUN: ld.lld2 -shared %t.o %td.so -o %t.so +# RUN: llvm-readobj -sections -dyn-symbols -dynamic-table %t.so \ +# RUN: | FileCheck -check-prefix=DSO %s + +# REQUIRES: mips + +# EXE: Sections [ +# EXE: Name: .dynamic +# EXE-NEXT: Type: SHT_DYNAMIC +# EXE-NEXT: Flags [ +# EXE-NEXT: SHF_ALLOC +# EXE-NEXT: ] +# EXE: Name: .rld_map +# EXE-NEXT: Type: SHT_PROGBITS +# EXE-NEXT: Flags [ +# EXE-NEXT: SHF_ALLOC +# EXE-NEXT: SHF_WRITE +# EXE-NEXT: ] +# EXE-NEXT: Address: [[RLDMAPADDR:0x[0-9a-f]+]] +# EXE-NEXT: Offset: +# EXE-NEXT: Size: 4 +# EXE: Name: .got +# EXE-NEXT: Type: SHT_PROGBITS +# EXE-NEXT: Flags [ (0x10000003) +# EXE-NEXT: SHF_ALLOC +# EXE-NEXT: SHF_WRITE +# EXE-NEXT: ] +# EXE-NEXT: Address: [[GOTADDR:0x[0-9a-f]+]] +# EXE-NEXT: Offset: +# EXE-NEXT: Size: 8 +# EXE: ] +# EXE: DynamicSection [ +# EXE-NEXT: Tag Type Name/Value +# EXE-DAG: 0x00000003 PLTGOT [[GOTADDR]] +# EXE-DAG: 0x70000001 MIPS_RLD_VERSION 1 +# EXE-DAG: 0x70000005 MIPS_FLAGS NOTPOT +# EXE-DAG: 0x70000006 MIPS_BASE_ADDRESS +# EXE-DAG: 0x7000000A MIPS_LOCAL_GOTNO 2 +# EXE-DAG: 0x70000011 MIPS_SYMTABNO 1 +# EXE-DAG: 0x70000013 MIPS_GOTSYM 0x1 +# EXE-DAG: 0x70000016 MIPS_RLD_MAP [[RLDMAPADDR]] +# EXE: ] + +# DSO: Sections [ +# DSO: Name: .dynamic +# DSO-NEXT: Type: SHT_DYNAMIC +# DSO-NEXT: Flags [ +# DSO-NEXT: SHF_ALLOC +# DSO-NEXT: ] +# DSO: Name: .got +# DSO-NEXT: Type: SHT_PROGBITS +# DSO-NEXT: Flags [ (0x10000003) +# DSO-NEXT: SHF_ALLOC +# DSO-NEXT: SHF_WRITE +# DSO-NEXT: ] +# DSO-NEXT: Address: [[GOTADDR:0x[0-9a-f]+]] +# DSO-NEXT: Offset: +# DSO-NEXT: Size: 8 +# DSO: ] +# DSO: DynamicSymbols [ +# DSO: Name: @ +# DSO: Name: _gp@ +# DSO: Name: __start@ +# DSO: Name: _foo@ +# DSO: ] +# DSO: DynamicSection [ +# DSO-NEXT: Tag Type Name/Value +# DSO-DAG: 0x00000003 PLTGOT [[GOTADDR]] +# DSO-DAG: 0x70000001 MIPS_RLD_VERSION 1 +# DSO-DAG: 0x70000005 MIPS_FLAGS NOTPOT +# DSO-DAG: 0x70000006 MIPS_BASE_ADDRESS 0x0 +# DSO-DAG: 0x7000000A MIPS_LOCAL_GOTNO 2 +# DSO-DAG: 0x70000011 MIPS_SYMTABNO 4 +# DSO-DAG: 0x70000013 MIPS_GOTSYM 0x4 +# DSO: ] + + .text + .globl __start,_foo + .type _foo,@function +__start: + nop Index: lld/trunk/test/elf2/mips-got-relocs.s =================================================================== --- lld/trunk/test/elf2/mips-got-relocs.s +++ lld/trunk/test/elf2/mips-got-relocs.s @@ -68,25 +68,25 @@ # EXE_DIS_EL: 20000: 18 80 02 3c lui $2, 32792 # DSO_SYM: Sections: -# DSO_SYM: .got 0000000c 0000000000020034 DATA +# DSO_SYM: .got 0000000c 0000000000020004 DATA # DSO_SYM: SYMBOL TABLE: -# DSO_SYM: 00028024 *ABS* 00000000 _gp +# DSO_SYM: 00027ff4 *ABS* 00000000 _gp # ^-- .got + GP offset (0x7ff0) # DSO_SYM: 00020000 g .data 00000004 v1 # DSO_GOT_BE: Contents of section .got: -# DSO_GOT_BE: 20034 00000000 80000000 00020000 +# DSO_GOT_BE: 20004 00000000 80000000 00020000 # ^ ^ ^-- v1 (0x20000) # | +-- Module pointer (0x80000000) # +-- Lazy resolver (0x0) # DSO_GOT_EL: Contents of section .got: -# DSO_GOT_EL: 20034 00000000 00000080 00000200 +# DSO_GOT_EL: 20004 00000000 00000080 00000200 # ^ ^ ^-- v1 (0x20000) # | +-- Module pointer (0x80000000) # +-- Lazy resolver (0x0) -# v1GotAddr (0x2003c) - _gp (0x28024) = -0x7fe8 => 0x8018 = 32792 +# v1GotAddr (0x2000c) - _gp (0x27ff4) = -0x7fe8 => 0x8018 = 32792 # DSO_DIS_BE: 10000: 3c 02 80 18 lui $2, 32792 # DSO_DIS_EL: 10000: 18 80 02 3c lui $2, 32792