Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -64,6 +64,7 @@ bool ZNodelete = false; bool ZNow = false; bool ZOrigin = false; + bool ZRelro = false; ELFKind EKind = ELFNoneKind; uint16_t EMachine = llvm::ELF::EM_NONE; uint64_t EntryAddr = -1; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -186,6 +186,10 @@ Config->ZNow = true; else if (S == "origin") Config->ZOrigin = true; + else if (S == "relro") + Config->ZRelro = true; + else if (S == "norelro") + Config->ZRelro = false; } for (auto *Arg : Args) { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -309,6 +309,19 @@ .Default(1); } +// If RELRO is enabled then the ELF sections are reordered so that the ELF +// internal data sections (.got, .dtors, etc.) precede the program's data +// sections (.data and .bss). +// .got.plt should go after .got because in case of partial RELRO .got will +// be included into GNU_RELRO but .got.plt will still be writable. +static int8_t getRelroSectionRank(StringRef SectionName) { + return StringSwitch(SectionName) + .Case(".got", 1) + .Case(".got.plt", 2) + .Case(".data", 3) + .Default(0); +} + // Output section ordering is determined by this function. template static bool compareOutputSections(OutputSectionBase *A, @@ -365,13 +378,20 @@ if (AIsNoBits != BIsNoBits) return BIsNoBits; + int8_t RankA = 0; + int8_t RankB = 0; + if (Config->ZRelro) { + RankA = getRelroSectionRank(A->getName()); + RankB = getRelroSectionRank(B->getName()); + } + // Some architectures have additional ordering restrictions for sections // within the same PT_LOAD. - if (Config->EMachine == EM_PPC64) + if (RankA == RankB && Config->EMachine == EM_PPC64) return getPPC64SectionRank(A->getName()) < getPPC64SectionRank(B->getName()); - return false; + return RankA < RankB; } // Until this function is called, common symbols do not belong to any section. @@ -675,6 +695,7 @@ setPhdr(&Phdrs[++PhdrIdx], PT_LOAD, PF_R, 0, getVAStart(), FileOff, Target->getPageSize()); + Elf_Phdr GnuRelroPhdr = {}; // Create phdrs as we assign VAs and file offsets to all output sections. SmallPtrSet Closed; for (OutputSectionBase *Sec : OutputSections) { @@ -697,6 +718,21 @@ } } + if (Config->ZRelro && !GnuRelroPhdr.p_filesz) { + StringRef SectionName = Sec->getName(); + // If section name is .data or .bss, we should calculate the current gnu + // relro size and set the header`s properties. + // If not -z now then it is a partial relro and non-PLT GOT is read-only + // but .got.plt will be writeable. + bool FinishHeader = (SectionName == ".data" || SectionName == ".bss") || + (SectionName == ".got.plt" && !Config->ZNow); + if (FinishHeader) { + Elf_Phdr *Last = &Phdrs[PhdrIdx]; + setPhdr(&GnuRelroPhdr, PT_GNU_RELRO, PF_R, Last->p_offset, + Last->p_vaddr, VA - Last->p_vaddr, 1); + } + } + if (consumesVirtualAddressSpace(Sec)) { VA = RoundUpToAlignment(VA, Sec->getAlign()); Sec->setVA(VA); @@ -721,6 +757,11 @@ copyPhdr(Interp, Out::Interp); } + if (GnuRelroPhdr.p_filesz) { + Elf_Phdr *PH = &Phdrs[++PhdrIdx]; + *PH = GnuRelroPhdr; + } + // Add space for section headers. SectionHeaderOff = RoundUpToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4); FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr); @@ -743,6 +784,8 @@ ++I; } } + if (Config->ZRelro) + ++I; return I; } Index: test/elf2/relro.s =================================================================== --- test/elf2/relro.s +++ test/elf2/relro.s @@ -0,0 +1,215 @@ +// 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/shared.s -o %t2.o +// RUN: ld.lld2 -shared %t2.o -o %t2.so +// RUN: ld.lld2 %t.o %t2.so -z now -z relro -o %t +// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data %t | FileCheck --check-prefix=FULLRELRO %s +// RUN: ld.lld2 %t.o %t2.so -z relro -o %t +// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data %t | FileCheck --check-prefix=PARTRELRO %s +// RUN: ld.lld2 %t.o %t2.so -z norelro -o %t +// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data %t | FileCheck --check-prefix=NORELRO %s +// RUN: ld.lld2 %t.o %t2.so -o %t +// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data %t | FileCheck --check-prefix=NORELRO %s +// REQUIRES: x86 + +// FULLRELRO: Section { +// FULLRELRO: Index: 9 +// FULLRELRO-NEXT: Name: .got +// FULLRELRO-NEXT: Type: SHT_PROGBITS +// FULLRELRO-NEXT: Flags [ +// FULLRELRO-NEXT: SHF_ALLOC +// FULLRELRO-NEXT: SHF_WRITE +// FULLRELRO-NEXT: ] +// FULLRELRO-NEXT: Address: 0x12100 +// FULLRELRO-NEXT: Offset: 0x2100 +// FULLRELRO-NEXT: Size: 8 +// FULLRELRO-NEXT: Link: 0 +// FULLRELRO-NEXT: Info: 0 +// FULLRELRO-NEXT: AddressAlignment: 8 +// FULLRELRO-NEXT: EntrySize: 0 +// FULLRELRO-NEXT: SectionData ( +// FULLRELRO-NEXT: 0000: 00000000 00000000 +// FULLRELRO-NEXT: ) +// FULLRELRO-NEXT: } +// FULLRELRO-NEXT: Section { +// FULLRELRO-NEXT: Index: 10 +// FULLRELRO-NEXT: Name: .got.plt +// FULLRELRO-NEXT: Type: SHT_PROGBITS +// FULLRELRO-NEXT: Flags [ +// FULLRELRO-NEXT: SHF_ALLOC +// FULLRELRO-NEXT: SHF_WRITE +// FULLRELRO-NEXT: ] +// FULLRELRO-NEXT: Address: 0x12108 +// FULLRELRO-NEXT: Offset: 0x2108 +// FULLRELRO-NEXT: Size: 32 +// FULLRELRO-NEXT: Link: 0 +// FULLRELRO-NEXT: Info: 0 +// FULLRELRO-NEXT: AddressAlignment: 8 +// FULLRELRO-NEXT: EntrySize: 0 +// FULLRELRO-NEXT: SectionData ( +// FULLRELRO-NEXT: 0000: +// FULLRELRO-NEXT: 0010: +// FULLRELRO-NEXT: ) +// FULLRELRO-NEXT: } +// FULLRELRO-NEXT: Section { +// FULLRELRO-NEXT: Index: 11 +// FULLRELRO-NEXT: Name: .data +// FULLRELRO-NEXT: Type: SHT_PROGBITS +// FULLRELRO-NEXT: Flags [ +// FULLRELRO-NEXT: SHF_ALLOC +// FULLRELRO-NEXT: SHF_WRITE +// FULLRELRO-NEXT: ] +// FULLRELRO-NEXT: Address: 0x12128 +// FULLRELRO-NEXT: Offset: 0x2128 +// FULLRELRO-NEXT: Size: 0 +// FULLRELRO-NEXT: Link: 0 +// FULLRELRO-NEXT: Info: 0 +// FULLRELRO-NEXT: AddressAlignment: 4 +// FULLRELRO-NEXT: EntrySize: 0 +// FULLRELRO-NEXT: SectionData ( +// FULLRELRO-NEXT: ) +// FULLRELRO-NEXT: } +// FULLRELRO-NEXT: Section { +// FULLRELRO-NEXT: Index: 12 +// FULLRELRO-NEXT: Name: .bss +// FULLRELRO-NEXT: Type: SHT_NOBITS +// FULLRELRO-NEXT: Flags [ +// FULLRELRO-NEXT: SHF_ALLOC +// FULLRELRO-NEXT: SHF_WRITE +// FULLRELRO-NEXT: ] +// FULLRELRO-NEXT: Address: 0x12128 +// FULLRELRO-NEXT: Offset: 0x2128 +// FULLRELRO-NEXT: Size: 0 +// FULLRELRO-NEXT: Link: 0 +// FULLRELRO-NEXT: Info: 0 +// FULLRELRO-NEXT: AddressAlignment: 4 +// FULLRELRO-NEXT: EntrySize: 0 +// FULLRELRO-NEXT: } +// FULLRELRO: ProgramHeaders [ +// FULLRELRO: Type: PT_LOAD +// FULLRELRO: Offset: 0x2000 +// FULLRELRO-NEXT: VirtualAddress: [[RWADDR:.*]] +// FULLRELRO-NEXT: PhysicalAddress: +// FULLRELRO-NEXT: FileSize: [[RWSZ:.*]] +// FULLRELRO-NEXT: MemSize: [[RWSZ]] +// FULLRELRO-NEXT: Flags [ +// FULLRELRO-NEXT: PF_R +// FULLRELRO-NEXT: PF_W +// FULLRELRO-NEXT: ] +// FULLRELRO-NEXT: Alignment: 4096 +// FULLRELRO-NEXT:} +// FULLRELRO: Type: PT_GNU_RELRO +// FULLRELRO-NEXT: Offset: 0x2000 +// FULLRELRO-NEXT: VirtualAddress: [[RWADDR]] +// FULLRELRO-NEXT: PhysicalAddress: +// FULLRELRO-NEXT: FileSize: [[RWSZ]] +// FULLRELRO-NEXT: MemSize: [[RWSZ]] +// FULLRELRO-NEXT: Flags [ +// FULLRELRO-NEXT: PF_R +// FULLRELRO-NEXT: ] +// FULLRELRO-NEXT: Alignment: 1 +// FULLRELRO-NEXT:} + +// PARTRELRO: Section { +// PARTRELRO: Index: 9 +// PARTRELRO-NEXT: Name: .got +// PARTRELRO-NEXT: Type: SHT_PROGBITS +// PARTRELRO-NEXT: Flags [ +// PARTRELRO-NEXT: SHF_ALLOC +// PARTRELRO-NEXT: SHF_WRITE +// PARTRELRO-NEXT: ] +// PARTRELRO-NEXT: Address: 0x120E0 +// PARTRELRO-NEXT: Offset: 0x20E0 +// PARTRELRO-NEXT: Size: 8 +// PARTRELRO-NEXT: Link: 0 +// PARTRELRO-NEXT: Info: 0 +// PARTRELRO-NEXT: AddressAlignment: 8 +// PARTRELRO-NEXT: EntrySize: 0 +// PARTRELRO-NEXT: SectionData ( +// PARTRELRO-NEXT: 0000: +// PARTRELRO-NEXT: ) +// PARTRELRO-NEXT: } +// PARTRELRO-NEXT: Section { +// PARTRELRO-NEXT: Index: 10 +// PARTRELRO-NEXT: Name: .got.plt +// PARTRELRO-NEXT: Type: SHT_PROGBITS +// PARTRELRO-NEXT: Flags [ +// PARTRELRO-NEXT: SHF_ALLOC +// PARTRELRO-NEXT: SHF_WRITE +// PARTRELRO-NEXT: ] +// PARTRELRO-NEXT: Address: 0x120E8 +// PARTRELRO-NEXT: Offset: 0x20E8 +// PARTRELRO-NEXT: Size: 32 +// PARTRELRO-NEXT: Link: 0 +// PARTRELRO-NEXT: Info: 0 +// PARTRELRO-NEXT: AddressAlignment: 8 +// PARTRELRO-NEXT: EntrySize: 0 +// PARTRELRO-NEXT: SectionData ( +// PARTRELRO-NEXT: 0000: +// PARTRELRO-NEXT: 0010: +// PARTRELRO-NEXT: ) +// PARTRELRO-NEXT: } +// PARTRELRO-NEXT: Section { +// PARTRELRO-NEXT: Index: 11 +// PARTRELRO-NEXT: Name: .data +// PARTRELRO-NEXT: Type: SHT_PROGBITS +// PARTRELRO-NEXT: Flags [ +// PARTRELRO-NEXT: SHF_ALLOC +// PARTRELRO-NEXT: SHF_WRITE +// PARTRELRO-NEXT: ] +// PARTRELRO-NEXT: Address: 0x12108 +// PARTRELRO-NEXT: Offset: 0x2108 +// PARTRELRO-NEXT: Size: 0 +// PARTRELRO-NEXT: Link: 0 +// PARTRELRO-NEXT: Info: 0 +// PARTRELRO-NEXT: AddressAlignment: 4 +// PARTRELRO-NEXT: EntrySize: 0 +// PARTRELRO-NEXT: SectionData ( +// PARTRELRO-NEXT: ) +// PARTRELRO-NEXT: } +// PARTRELRO-NEXT: Section { +// PARTRELRO-NEXT: Index: 12 +// PARTRELRO-NEXT: Name: .bss +// PARTRELRO-NEXT: Type: SHT_NOBITS +// PARTRELRO-NEXT: Flags [ +// PARTRELRO-NEXT: SHF_ALLOC +// PARTRELRO-NEXT: SHF_WRITE +// PARTRELRO-NEXT: ] +// PARTRELRO-NEXT: Address: 0x12108 +// PARTRELRO-NEXT: Offset: 0x2108 +// PARTRELRO-NEXT: Size: 0 +// PARTRELRO-NEXT: Link: 0 +// PARTRELRO-NEXT: Info: 0 +// PARTRELRO-NEXT: AddressAlignment: 4 +// PARTRELRO-NEXT: EntrySize: 0 +// PARTRELRO-NEXT: } +// 232 + .got.plt size (32) = 264 +// PARTRELRO: ProgramHeader { +// PARTRELRO: Type: PT_LOAD +// PARTRELRO: Offset: 0x2000 +// PARTRELRO-NEXT: VirtualAddress: [[RWADDR:.*]] +// PARTRELRO-NEXT: PhysicalAddress: +// PARTRELRO-NEXT: FileSize: 264 +// PARTRELRO-NEXT: MemSize: 264 +// PARTRELRO-NEXT: Flags [ (0x6) +// PARTRELRO-NEXT: PF_R (0x4) +// PARTRELRO-NEXT: PF_W (0x2) +// PARTRELRO-NEXT: ] +// PARTRELRO-NEXT: Alignment: 4096 +// PARTRELRO: Type: PT_GNU_RELRO +// PARTRELRO-NEXT: Offset: 0x2000 +// PARTRELRO-NEXT: VirtualAddress: [[RWADDR]] +// PARTRELRO-NEXT: PhysicalAddress: +// PARTRELRO-NEXT: FileSize: 232 +// PARTRELRO-NEXT: MemSize: 232 +// PARTRELRO-NEXT: Flags [ +// PARTRELRO-NEXT: PF_R +// PARTRELRO-NEXT: ] +// PARTRELRO-NEXT: Alignment: 1 + +// NORELRO: ProgramHeaders [ +// NORELRO-NOT: PT_GNU_RELRO + +.global _start +_start: + .long bar + jmp *bar@GOTPCREL(%rip)