Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -145,6 +145,7 @@ bool ZNow; bool ZOrigin; bool ZRelro; + bool ZRodynamic; bool ZText; bool ExitEarly; bool ZWxneeded; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -688,6 +688,7 @@ Config->ZNow = hasZOption(Args, "now"); Config->ZOrigin = hasZOption(Args, "origin"); Config->ZRelro = !hasZOption(Args, "norelro"); + Config->ZRodynamic = hasZOption(Args, "rodynamic"); Config->ZStackSize = getZOptionValue(Args, "stack-size", 0); Config->ZText = !hasZOption(Args, "notext"); Config->ZWxneeded = hasZOption(Args, "wxneeded"); Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1005,10 +1005,11 @@ ".dynamic") { this->Entsize = ELFT::Is64Bits ? 16 : 8; - // .dynamic section is not writable on MIPS. + // .dynamic section is not writable on MIPS and on Fuchsia OS + // which passes -z rodynamic. // 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->EMachine == EM_MIPS || Config->ZRodynamic) this->Flags = SHF_ALLOC; addEntries(); @@ -1053,7 +1054,15 @@ if (DtFlags1) add({DT_FLAGS_1, DtFlags1}); - if (!Config->Shared && !Config->Relocatable) + // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We + // need it for each process, so we don't write it for DSOs. The loader writes + // the pointer into this entry. + // + // DT_DEBUG is the only .dynamic entry that needs to be written to. Some + // systems (currently only Fuchsia OS) provide other means to give the + // debugger this information. Such systems may choose make .dynamic read-only. + // If the target is such a system (used -z rodynamic) don't write DT_DEBUG. + if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic) add({DT_DEBUG, (uint64_t)0}); } Index: test/ELF/Inputs/rodynamic.s =================================================================== --- /dev/null +++ test/ELF/Inputs/rodynamic.s @@ -0,0 +1,4 @@ +.global foo +.type foo, @function +foo: + ret Index: test/ELF/rodynamic.s =================================================================== --- /dev/null +++ test/ELF/rodynamic.s @@ -0,0 +1,33 @@ +# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux +# RUN: llvm-mc %p/Inputs/rodynamic.s -o %t.so.o -filetype=obj -triple=x86_64-pc-linux +# RUN: ld.lld -shared %t.so.o -o %t.so +# RUN: ld.lld %t.o %t.so -o %t.exe +# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=DEFDEBUG %s +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=DEFSEC %s +# RUN: ld.lld -shared -z rodynamic %t.so.o -o %t.so +# RUN: ld.lld -z rodynamic %t.o %t.so -o %t.exe +# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=RODEBUG %s +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=ROSEC %s + +.globl _start +_start: + call foo + +# DEFDEBUG: DEBUG + +# DEFSEC: Section { +# DEFSEC: Name: .dynamic +# DEFSEC-NEXT: Type: SHT_DYNAMIC +# DEFSEC-NEXT: Flags [ +# DEFSEC-NEXT: SHF_ALLOC +# DEFSEC-NEXT: SHF_WRITE +# DEFSEC-NEXT: ] + +# RODEBUG-NOT: DEBUG + +# ROSEC: Section { +# ROSEC: Name: .dynamic +# ROSEC-NEXT: Type: SHT_DYNAMIC +# ROSEC-NEXT: Flags [ +# ROSEC-NEXT: SHF_ALLOC +# ROSEC-NEXT: ]