Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -144,6 +144,7 @@ bool ZNodlopen; bool ZNow; bool ZOrigin; + bool ZReadOnlyDynamic; bool ZRelro; bool ZText; bool ExitEarly; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -687,6 +687,7 @@ Config->ZNodlopen = hasZOption(Args, "nodlopen"); Config->ZNow = hasZOption(Args, "now"); Config->ZOrigin = hasZOption(Args, "origin"); + Config->ZReadOnlyDynamic = hasZOption(Args, "rodynamic"); Config->ZRelro = !hasZOption(Args, "norelro"); Config->ZStackSize = getZOptionValue(Args, "stack-size", 0); Config->ZText = !hasZOption(Args, "notext"); @@ -787,6 +788,8 @@ Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi; Config->Pic = Config->Pie || Config->Shared; Config->Wordsize = Config->Is64 ? 8 : 4; + //MIPS must unconditionally set ZReadOnlyDynamic + Config->ZReadOnlyDynamic = Machine == EM_MIPS ? true : Config->ZReadOnlyDynamic; } // Returns a value of "-format" option. Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -336,6 +336,19 @@ int64_t Addend; }; +// This is a section to hold a space within the data segment +// of the executable file which is pointed to by the +// DT_MIPS_RLD_MAP/DT_DEBUG_INDIRECT entry. This was a MIPS specific +// section but it has other uses as well. +// See "Dynamic section" in Chapter 5 in the following document: +// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf +class RldMapSection : public SyntheticSection { +public: + RldMapSection(); + size_t getSize() const override { return Config->Wordsize; } + void writeTo(uint8_t *Buf) override; +}; + template class DynamicSection final : public SyntheticSection { typedef typename ELFT::Dyn Elf_Dyn; typedef typename ELFT::Rel Elf_Rel; @@ -701,17 +714,6 @@ Elf_Mips_RegInfo Reginfo; }; -// 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 -class MipsRldMapSection : public SyntheticSection { -public: - MipsRldMapSection(); - size_t getSize() const override { return Config->Wordsize; } - void writeTo(uint8_t *Buf) override; -}; - class ARMExidxSentinelSection : public SyntheticSection { public: ARMExidxSentinelSection(); @@ -762,7 +764,7 @@ static GotPltSection *GotPlt; static IgotPltSection *IgotPlt; static MipsGotSection *MipsGot; - static MipsRldMapSection *MipsRldMap; + static RldMapSection *RldMap; static PltSection *Plt; static PltSection *Iplt; static StringTableSection *ShStrTab; Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -999,6 +999,21 @@ } } +RldMapSection::RldMapSection() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, + ".rld_map") {} + +void RldMapSection::writeTo(uint8_t *Buf) { + // Apply filler from linker script. + Optional Fill = Script->getFiller(this->OutSec); + if (!Fill || *Fill == 0) + return; + + uint64_t Filler = *Fill; + Filler = (Filler << 32) | Filler; + memcpy(Buf, &Filler, getSize()); +} + // Returns the number of version definition entries. Because the first entry // is for the version definition itself, it is the number of versioned symbols // plus one. Note that we don't support multiple versions yet. @@ -1010,10 +1025,11 @@ ".dynamic") { this->Entsize = ELFT::Is64Bits ? 16 : 8; - // .dynamic section is not writable on MIPS. + // For security the user may want to make .dynamic read only. + // Additionally .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) + if (Config->ZReadOnlyDynamic) this->Flags = SHF_ALLOC; addEntries(); @@ -1058,7 +1074,8 @@ if (DtFlags1) add({DT_FLAGS_1, DtFlags1}); - if (!Config->Shared && !Config->Relocatable) + //If .dynamic is read only then DT_DEBUG will cause a segfault. + if (!Config->Shared && !Config->Relocatable && !Config->ZReadOnlyDynamic) add({DT_DEBUG, (uint64_t)0}); } @@ -1144,9 +1161,9 @@ else add({DT_MIPS_GOTSYM, In::DynSymTab->getNumSymbols()}); add({DT_PLTGOT, InX::MipsGot}); - if (InX::MipsRldMap) - add({DT_MIPS_RLD_MAP, InX::MipsRldMap}); } + if (InX::RldMap) + add({DT_DEBUG_INDIRECT, InX::RldMap}); this->OutSec->Link = this->Link; @@ -2177,21 +2194,6 @@ return Builder.getSize(); } -MipsRldMapSection::MipsRldMapSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, - ".rld_map") {} - -void MipsRldMapSection::writeTo(uint8_t *Buf) { - // Apply filler from linker script. - Optional Fill = Script->getFiller(this->OutSec); - if (!Fill || *Fill == 0) - return; - - uint64_t Filler = *Fill; - Filler = (Filler << 32) | Filler; - memcpy(Buf, &Filler, getSize()); -} - ARMExidxSentinelSection::ARMExidxSentinelSection() : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, Config->Wordsize, ".ARM.exidx") {} @@ -2249,7 +2251,7 @@ GotPltSection *InX::GotPlt; IgotPltSection *InX::IgotPlt; MipsGotSection *InX::MipsGot; -MipsRldMapSection *InX::MipsRldMap; +RldMapSection *InX::RldMap; PltSection *InX::Plt; PltSection *InX::Iplt; StringTableSection *InX::ShStrTab; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -355,10 +355,6 @@ bool HasDynSymTab = !Symtab::X->getSharedFiles().empty() || Config->Pic || Config->ExportDynamic; if (Config->EMachine == EM_MIPS) { - if (!Config->Shared && HasDynSymTab) { - InX::MipsRldMap = make(); - Add(InX::MipsRldMap); - } if (auto *Sec = MipsAbiFlagsSection::create()) Add(Sec); if (auto *Sec = MipsOptionsSection::create()) @@ -367,6 +363,13 @@ Add(Sec); } + //If ZReadOnlyDynamic is set then we're going to need to emit a + //RldMapSection for DT_DEBUG_INDIRECT/DT_MIPS_RLD_MAP to point to. + if(!Config->Shared && HasDynSymTab && Config->ZReadOnlyDynamic) { + In::RldMap = make(); + Add(In::RldMap); + } + if (HasDynSymTab) { In::DynSymTab = make>(*InX::DynStrTab); Add(In::DynSymTab); Index: test/ELF/Inputs/rodynamic.s =================================================================== --- /dev/null +++ test/ELF/Inputs/rodynamic.s @@ -0,0 +1,4 @@ + .text + .globl _foo +_foo: + ret Index: test/ELF/rodynamic.s =================================================================== --- /dev/null +++ test/ELF/rodynamic.s @@ -0,0 +1,27 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/rodynamic.s -o %td.o +# RUN: ld.lld -shared %td.o -o %td.so +# RUN: ld.lld -z rodynamic %t.o %td.so -o %t.exe +# RUN: llvm-readobj -sections -dynamic-table %t.exe | FileCheck %s + + .text + .globl __start,_foo + .type _foo,@function +__start: + ret + +# CHECK: Section { +# CHECK: Name: .dynamic +# CHECK-NEXT: Type: SHT_DYNAMIC +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK: Name: .rld_map +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: [[RLDMAPADDR:0x[0-9a-f]+]] +# CHECK: DynamicSection [ +# CHECK: 0x0000000070000016 unknown [[RLDMAPADDR]]