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 @@ -45,6 +45,8 @@ void scanRelocs(const InputSection &C, iterator_range *> Rels); void scanRelocs(const InputSection &C); + void updateRelRo(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr, + OutputSectionBase *Sec, uintX_t VA); void assignAddresses(); void openFile(StringRef OutputPath); void writeHeader(); @@ -319,6 +321,12 @@ .Default(1); } +template static bool isRelroSection(OutputSectionBase *Sec) { + if (Sec == Out::GotPlt) + return Config->ZNow; + return (Sec->getName() != ".data" && Sec->getType() != SHT_NOBITS); +} + // Output section ordering is determined by this function. template static bool compareOutputSections(OutputSectionBase *A, @@ -375,6 +383,11 @@ if (AIsNoBits != BIsNoBits) return BIsNoBits; + bool AIsRelRo = isRelroSection(A); + bool BIsRelRo = isRelroSection(B); + if (AIsRelRo != BIsRelRo) + return AIsRelRo; + // Some architectures have additional ordering restrictions for sections // within the same PT_LOAD. if (Config->EMachine == EM_PPC64) @@ -673,6 +686,23 @@ return Ret; } +template +void Writer::updateRelRo(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr, + OutputSectionBase *Sec, uintX_t VA) { + + if (!Config->ZRelro || !(Cur->p_flags & PF_W)) + return; + + if (isRelroSection(Sec)) { + if (!GnuRelroPhdr->p_type) + setPhdr(GnuRelroPhdr, PT_GNU_RELRO, PF_R, Cur->p_offset, Cur->p_vaddr, + VA - Cur->p_vaddr, 1 /*p_align*/); + + GnuRelroPhdr->p_filesz = VA - Cur->p_vaddr; + GnuRelroPhdr->p_memsz = VA - Cur->p_vaddr; + } +} + // Visits all sections to create PHDRs and to assign incremental, // non-overlapping addresses to output sections. template void Writer::assignAddresses() { @@ -699,6 +729,7 @@ setPhdr(&Phdrs[++PhdrIdx], PT_LOAD, PF_R, 0, Target->getVAStart(), FileOff, Target->getPageSize()); + Elf_Phdr GnuRelroPhdr = {}; Elf_Phdr TlsPhdr{}; uintX_t ThreadBSSOffset = 0; // Create phdrs as we assign VAs and file offsets to all output sections. @@ -732,6 +763,8 @@ VA = RoundUpToAlignment(VA, Sec->getAlign()); Sec->setVA(VA); VA += Sec->getSize(); + + updateRelRo(&Phdrs[PhdrIdx], &GnuRelroPhdr, Sec, VA); } } @@ -767,6 +800,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); @@ -798,6 +836,8 @@ } if (Tls) ++I; + if (Config->ZRelro) + ++I; return I; } Index: test/elf2/mips-got-relocs.s =================================================================== --- test/elf2/mips-got-relocs.s +++ test/elf2/mips-got-relocs.s @@ -45,21 +45,21 @@ .word 0 # EXE_SYM: Sections: -# EXE_SYM: .got 0000000c 0000000000030004 DATA +# EXE_SYM: .got 0000000c 0000000000030000 DATA # EXE_SYM: SYMBOL TABLE: -# EXE_SYM: 00037ff4 *ABS* 00000000 _gp +# EXE_SYM: 00037ff0 *ABS* 00000000 _gp # ^-- .got + GP offset (0x7ff0) -# EXE_SYM: 00030000 g .data 00000004 v1 +# EXE_SYM: 00030010 g .data 00000004 v1 # EXE_GOT_BE: Contents of section .got: -# EXE_GOT_BE: 30004 00000000 80000000 00030000 -# ^ ^ ^-- v1 (0x30000) +# EXE_GOT_BE: 30000 00000000 80000000 00030010 +# ^ ^ ^-- v1 (0x30010) # | +-- Module pointer (0x80000000) # +-- Lazy resolver (0x0) # EXE_GOT_EL: Contents of section .got: -# EXE_GOT_EL: 30004 00000000 00000080 00000300 -# ^ ^ ^-- v1 (0x30000) +# EXE_GOT_EL: 30000 00000000 00000080 10000300 +# ^ ^ ^-- v1 (0x30010) # | +-- Module pointer (0x80000000) # +-- Lazy resolver (0x0) @@ -68,21 +68,21 @@ # EXE_DIS_EL: 20000: 18 80 02 3c lui $2, 32792 # DSO_SYM: Sections: -# DSO_SYM: .got 0000000c 0000000000020034 DATA +# DSO_SYM: .got 0000000c 0000000000020030 DATA # DSO_SYM: SYMBOL TABLE: -# DSO_SYM: 00028024 *ABS* 00000000 _gp +# DSO_SYM: 00028020 *ABS* 00000000 _gp # ^-- .got + GP offset (0x7ff0) -# DSO_SYM: 00020000 g .data 00000004 v1 +# DSO_SYM: 00020040 g .data 00000004 v1 # DSO_GOT_BE: Contents of section .got: -# DSO_GOT_BE: 20034 00000000 80000000 00020000 -# ^ ^ ^-- v1 (0x20000) +# DSO_GOT_BE: 20030 00000000 80000000 00020040 +# ^ ^ ^-- v1 (0x20040) # | +-- Module pointer (0x80000000) # +-- Lazy resolver (0x0) # DSO_GOT_EL: Contents of section .got: -# DSO_GOT_EL: 20034 00000000 00000080 00000200 -# ^ ^ ^-- v1 (0x20000) +# DSO_GOT_EL: 20030 00000000 00000080 40000200 +# ^ ^ ^-- v1 (0x20040) # | +-- Module pointer (0x80000000) # +-- Lazy resolver (0x0) Index: test/elf2/relro.s =================================================================== --- test/elf2/relro.s +++ test/elf2/relro.s @@ -0,0 +1,224 @@ +// 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: 12 +// FULLRELRO-NEXT: Link: 0 +// FULLRELRO-NEXT: Info: 0 +// FULLRELRO-NEXT: AddressAlignment: +// FULLRELRO-NEXT: EntrySize: 0 +// FULLRELRO-NEXT: SectionData ( +// FULLRELRO-NEXT: 0000: +// 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: 0x12134 +// FULLRELRO-NEXT: Offset: 0x2134 +// FULLRELRO-NEXT: Size: 0 +// FULLRELRO-NEXT: Link: 0 +// FULLRELRO-NEXT: Info: 0 +// FULLRELRO-NEXT: AddressAlignment: +// FULLRELRO-NEXT: EntrySize: 0 +// FULLRELRO-NEXT: } +// 308 - sizeof(.data)(12) = 296 +// FULLRELRO: ProgramHeaders [ +// FULLRELRO: Type: PT_LOAD +// FULLRELRO: Offset: 0x2000 +// FULLRELRO-NEXT: VirtualAddress: [[RWADDR:.*]] +// FULLRELRO-NEXT: PhysicalAddress: +// FULLRELRO-NEXT: FileSize: 308 +// FULLRELRO-NEXT: MemSize: 308 +// 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: 0x +// FULLRELRO-NEXT: VirtualAddress: [[RWADDR]] +// FULLRELRO-NEXT: PhysicalAddress: +// FULLRELRO-NEXT: FileSize: 296 +// FULLRELRO-NEXT: MemSize: 296 +// 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: .data +// 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: 12 +// PARTRELRO-NEXT: Link: 0 +// PARTRELRO-NEXT: Info: 0 +// PARTRELRO-NEXT: AddressAlignment: 1 +// PARTRELRO-NEXT: EntrySize: 0 +// PARTRELRO-NEXT: SectionData ( +// PARTRELRO-NEXT: 0000: +// PARTRELRO-NEXT: ) +// PARTRELRO-NEXT: } +// PARTRELRO-NEXT: Section { +// PARTRELRO-NEXT: Index: 11 +// 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: 0x120F8 +// PARTRELRO-NEXT: Offset: 0x20F8 +// 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: 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: 0x12118 +// PARTRELRO-NEXT: Offset: 0x2118 +// PARTRELRO-NEXT: Size: 0 +// PARTRELRO-NEXT: Link: 0 +// PARTRELRO-NEXT: Info: 0 +// PARTRELRO-NEXT: AddressAlignment: 1 +// PARTRELRO-NEXT: EntrySize: 0 +// PARTRELRO-NEXT: } +// 232 + sizeof(.data)(12) + align(4) + sizeof(.got.plt)(32) = 280 +// PARTRELRO: ProgramHeader { +// PARTRELRO: Type: PT_LOAD +// PARTRELRO: Offset: 0x2000 +// PARTRELRO-NEXT: VirtualAddress: [[RWADDR:.*]] +// PARTRELRO-NEXT: PhysicalAddress: +// PARTRELRO-NEXT: FileSize: 280 +// PARTRELRO-NEXT: MemSize: 280 +// PARTRELRO-NEXT: Flags [ +// 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) + +.section .data,"aw" +.quad 0 + +.zero 4 +.bss Index: test/elf2/section-name.s =================================================================== --- test/elf2/section-name.s +++ test/elf2/section-name.s @@ -22,9 +22,9 @@ // CHECK: Name: .rodata // CHECK-NOT: Name: .text.a // CHECK: Name: .text -// CHECK-NOT: Name: .data.a -// CHECK: Name: .data // CHECK: Name: .foo.a // CHECK: Name: .foo +// CHECK-NOT: Name: .data.a +// CHECK: Name: .data // CHECK-NOT: Name: .bss.a // CHECK: Name: .bss