Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -118,6 +118,7 @@ void addEntry(SymbolBody *Sym); bool empty() const { return Entries.empty(); } uintX_t getEntryAddr(const SymbolBody &B) const; + const SymbolBody *getFirstEntry() const; private: std::vector Entries; @@ -359,6 +360,7 @@ static HashTableSection *HashTab; static InterpSection *Interp; static OutputSection *Bss; + static OutputSection *MipsRldMap; static OutputSectionBase *Opd; static uint8_t *OpdBuf; static PltSection *Plt; @@ -380,6 +382,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: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -88,6 +88,11 @@ return this->getVA() + B.GotIndex * sizeof(uintX_t); } +template +const SymbolBody *GotSection::getFirstEntry() const { + return Entries.empty() ? nullptr : Entries.front(); +} + template void GotSection::finalize() { this->Header.sh_size = (Target->getGotHeaderEntriesNum() + Entries.size()) * sizeof(uintX_t); @@ -460,6 +465,11 @@ 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() { @@ -478,7 +488,7 @@ if (Out::RelaPlt && Out::RelaPlt->hasRelocs()) { ++NumEntries; // DT_JMPREL ++NumEntries; // DT_PLTRELSZ - ++NumEntries; // DT_PLTGOT + ++NumEntries; // DT_PLTGOT or DT_MIPS_PLTGOT ++NumEntries; // DT_PLTREL } @@ -541,6 +551,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; @@ -571,7 +594,8 @@ if (Out::RelaPlt && Out::RelaPlt->hasRelocs()) { WritePtr(DT_JMPREL, Out::RelaPlt->getVA()); WriteVal(DT_PLTRELSZ, Out::RelaPlt->getSize()); - WritePtr(DT_PLTGOT, Out::GotPlt->getVA()); + WritePtr((Config->EMachine == EM_MIPS) ? DT_MIPS_PLTGOT : DT_PLTGOT, + Out::GotPlt->getVA()); WriteVal(DT_PLTREL, Out::RelaPlt->isRela() ? DT_RELA : DT_REL); } @@ -623,6 +647,27 @@ 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()); + if (const SymbolBody *B = Out::Got->getFirstEntry()) { + WriteVal(DT_MIPS_LOCAL_GOTNO, B->GotIndex); + WriteVal(DT_MIPS_GOTSYM, B->getDynamicSymbolTableIndex()); + } else { + WriteVal(DT_MIPS_LOCAL_GOTNO, Target->getGotHeaderEntriesNum()); + 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: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -22,7 +22,7 @@ class TargetInfo { public: unsigned getPageSize() const { return PageSize; } - uint64_t getVAStart() const { return VAStart; } + uint64_t getVAStart() const; unsigned getCopyReloc() const { return CopyReloc; } unsigned getPCRelReloc() const { return PCRelReloc; } unsigned getGotReloc() const { return GotReloc; } Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -154,6 +154,8 @@ TargetInfo::~TargetInfo() {} +uint64_t TargetInfo::getVAStart() const { return Config->Shared ? 0 : VAStart; } + bool TargetInfo::relocNeedsCopy(uint32_t Type, const SymbolBody &S) const { return false; } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -55,7 +55,6 @@ bool isOutputDynamic() const { return !Symtab.getSharedFiles().empty() || Config->Shared; } - uintX_t getVAStart() const { return Config->Shared ? 0 : Target->getVAStart(); } uintX_t getEntryAddr() const; int getPhdrsNum() const; @@ -594,8 +593,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 a data segment + // of executable file which is pointed to by 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 include .got section in 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); @@ -677,7 +691,7 @@ // Visits all sections to create PHDRs and to assign incremental, // non-overlapping addresses to output sections. template void Writer::assignAddresses() { - uintX_t VA = getVAStart() + sizeof(Elf_Ehdr); + uintX_t VA = Target->getVAStart() + sizeof(Elf_Ehdr); uintX_t FileOff = sizeof(Elf_Ehdr); // Calculate and reserve the space for the program header first so that @@ -697,7 +711,7 @@ Interp = &Phdrs[++PhdrIdx]; // Add the first PT_LOAD segment for regular output sections. - setPhdr(&Phdrs[++PhdrIdx], PT_LOAD, PF_R, 0, getVAStart(), FileOff, + setPhdr(&Phdrs[++PhdrIdx], PT_LOAD, PF_R, 0, Target->getVAStart(), FileOff, Target->getPageSize()); Elf_Phdr TlsPhdr{}; Index: test/elf2/Inputs/mips-dynamic.s =================================================================== --- /dev/null +++ test/elf2/Inputs/mips-dynamic.s @@ -0,0 +1,4 @@ + .text + .globl _foo +_foo: + nop Index: test/elf2/mips-dynamic.s =================================================================== --- /dev/null +++ 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: test/elf2/mips-got-relocs.s =================================================================== --- test/elf2/mips-got-relocs.s +++ 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