[PATCH v2] elf/x86: Place code after read-only data for --rosegment
H.J. Lu
hjl.tools@gmail.com
Mon Mar 30 14:55:30 GMT 2026
On Wed, Mar 25, 2026 at 9:49 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> commit e8e10743f7b207b21a1efb0cc9e42487080db013
> Author: Nick Clifton <nickc@redhat.com>
> Date: Thu Jun 13 15:10:15 2024 +0100
>
> Add --rosegment option to BFD linker to stop the '-z separate-code' from gen erating two read-only segments.
>
> added --rosegment option to generate one read-only segment with
> -z separate-code. But it puts the read-only data, which contains ELF
> headers and .note.gnu.build-id section, in the executable segment:
>
> Program Headers:
> Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
> LOAD 0x000000 0x00000000 0x00000000 0x00185 0x00185 R E 0x1000
> LOAD 0x001000 0x00001000 0x00001000 0x000d0 0x000d0 R 0x1000
> LOAD 0x001f78 0x00002f78 0x00002f78 0x0008c 0x0008c RW 0x1000
> DYNAMIC 0x001f78 0x00002f78 0x00002f78 0x00070 0x00070 RW 0x4
> NOTE 0x000154 0x00000154 0x00000154 0x00024 0x00024 R 0x4
> NOTE 0x00109c 0x0000109c 0x0000109c 0x00034 0x00034 R 0x4
> GNU_PROPERTY 0x00109c 0x0000109c 0x0000109c 0x00034 0x00034 R 0x4
> GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
> GNU_RELRO 0x001f78 0x00002f78 0x00002f78 0x00088 0x00088 R 0x1
>
> Section to Segment mapping:
> Segment Sections...
> 00 .note.gnu.build-id .text
> 01 .gnu.hash .dynsym .dynstr .rela.dyn .rodata .eh_frame .note.gnu.property
> 02 .dynamic .got.plt .data
> 03 .dynamic
> 04 .note.gnu.build-id
> 05 .note.gnu.property
> 06 .note.gnu.property
> 07
> 08 .dynamic .got.plt
>
> which defeats the purpose of -z separate-code. Update --rosegment to
> place code after read-only data:
>
> Program Headers:
> Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
> LOAD 0x000000 0x00000000 0x00000000 0x00248 0x00248 R 0x1000
> LOAD 0x001000 0x00001000 0x00001000 0x00005 0x00005 R E 0x1000
> LOAD 0x001f78 0x00002f78 0x00002f78 0x0008c 0x0008c RW 0x1000
> DYNAMIC 0x001f78 0x00002f78 0x00002f78 0x00070 0x00070 RW 0x4
> NOTE 0x000154 0x00000154 0x00000154 0x00024 0x00024 R 0x4
> NOTE 0x000214 0x00000214 0x00000214 0x00034 0x00034 R 0x4
> GNU_PROPERTY 0x000214 0x00000214 0x00000214 0x00034 0x00034 R 0x4
> GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
> GNU_RELRO 0x001f78 0x00002f78 0x00002f78 0x00088 0x00088 R 0x1
>
> Section to Segment mapping:
> Segment Sections...
> 00 .note.gnu.build-id .gnu.hash .dynsym .dynstr .rela.dyn .rodata .eh_frame .note.gnu.property
> 01 .text
> 02 .dynamic .got.plt .data
> 03 .dynamic
> 04 .note.gnu.build-id
> 05 .note.gnu.property
> 06 .note.gnu.property
> 07
> 08 .dynamic .got.plt
I am checking it in.
> PR ld/23704
> PR ld/30907
> PR ld/32191
> PR ld/34003
> * emulparams/elf32_x86_64.sh (ALL_TEXT_AFTER_RO): New.
> * emulparams/elf_i386.sh (ALL_TEXT_AFTER_RO): Likewise.
> * emulparams/elf_i386_be.sh (ALL_TEXT_AFTER_RO): Likewise.
> * emulparams/elf_i386_vxworks.sh (ALL_TEXT_AFTER_RO): Likewise.
> * emulparams/elf_iamcu.sh (ALL_TEXT_AFTER_RO): Likewise.
> * emulparams/elf_x86_64.sh (ALL_TEXT_AFTER_RO): Likewise.
> * scripttempl/elf.sc (ALL_TEXT_AFTER_RO): New. If set, place
> code after read-only data for -z separate-code --rosegment.
> * testsuite/ld-elf/pr30907-2.d: Skip x86 targets.
> * testsuite/ld-elf/pr34003.d: New file.
> * testsuite/ld-i386/pr32191.d: Updated.
> * testsuite/ld-x86-64/pr32191-x32.d: Likewise.
> * testsuite/ld-x86-64/pr32191.d: Likewise.
>
> Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> ---
> ld/emulparams/elf32_x86_64.sh | 1 +
> ld/emulparams/elf_i386.sh | 1 +
> ld/emulparams/elf_i386_be.sh | 1 +
> ld/emulparams/elf_i386_vxworks.sh | 1 +
> ld/emulparams/elf_iamcu.sh | 1 +
> ld/emulparams/elf_x86_64.sh | 1 +
> ld/scripttempl/elf.sc | 39 +++++++++++++++++-----------
> ld/testsuite/ld-elf/pr30907-2.d | 1 +
> ld/testsuite/ld-elf/pr34003.d | 13 ++++++++++
> ld/testsuite/ld-i386/pr32191.d | 4 ++-
> ld/testsuite/ld-x86-64/pr32191-x32.d | 4 ++-
> ld/testsuite/ld-x86-64/pr32191.d | 4 ++-
> 12 files changed, 53 insertions(+), 18 deletions(-)
> create mode 100644 ld/testsuite/ld-elf/pr34003.d
>
> diff --git a/ld/emulparams/elf32_x86_64.sh b/ld/emulparams/elf32_x86_64.sh
> index 8a07f50e47f..256ae31ed24 100644
> --- a/ld/emulparams/elf32_x86_64.sh
> +++ b/ld/emulparams/elf32_x86_64.sh
> @@ -35,6 +35,7 @@ OTHER_PLT_SECTIONS="
> "
> OTHER_GOT_RELOC_SECTIONS="
> .rela.tls ${RELOCATING-0} : { *(.rela.tls) }"
> +ALL_TEXT_AFTER_RO=yes
>
> if [ "x${host}" = "x${target}" ]; then
> case " $EMULATION_LIBPATH " in
> diff --git a/ld/emulparams/elf_i386.sh b/ld/emulparams/elf_i386.sh
> index 12d71f5ef9e..d093afb9fa3 100644
> --- a/ld/emulparams/elf_i386.sh
> +++ b/ld/emulparams/elf_i386.sh
> @@ -30,6 +30,7 @@ OTHER_PLT_SECTIONS="
> "
> OTHER_GOT_RELOC_SECTIONS="
> .rel.tls ${RELOCATING-0} : { *(.rel.tls) }"
> +ALL_TEXT_AFTER_RO=yes
>
> # Linux modify the default library search path to first include
> # a 32-bit specific directory.
> diff --git a/ld/emulparams/elf_i386_be.sh b/ld/emulparams/elf_i386_be.sh
> index dbe68e99e63..e13d07dec23 100644
> --- a/ld/emulparams/elf_i386_be.sh
> +++ b/ld/emulparams/elf_i386_be.sh
> @@ -13,3 +13,4 @@ TEMPLATE_NAME=elf
> EXTRA_EM_FILE="elf-x86"
> GENERATE_SHLIB_SCRIPT=yes
> NO_SMALL_DATA=yes
> +ALL_TEXT_AFTER_RO=yes
> diff --git a/ld/emulparams/elf_i386_vxworks.sh b/ld/emulparams/elf_i386_vxworks.sh
> index 40c809263d1..347842909aa 100644
> --- a/ld/emulparams/elf_i386_vxworks.sh
> +++ b/ld/emulparams/elf_i386_vxworks.sh
> @@ -11,6 +11,7 @@ EXTRA_EM_FILE="elf-x86"
> GENERATE_SHLIB_SCRIPT=yes
> GENERATE_PIE_SCRIPT=yes
> NO_SMALL_DATA=yes
> +ALL_TEXT_AFTER_RO=yes
> source_sh ${srcdir}/emulparams/vxworks.sh
> source_sh ${srcdir}/emulparams/extern_protected_data.sh
> source_sh ${srcdir}/emulparams/dynamic_undefined_weak.sh
> diff --git a/ld/emulparams/elf_iamcu.sh b/ld/emulparams/elf_iamcu.sh
> index c1582235eda..7377ddee350 100644
> --- a/ld/emulparams/elf_iamcu.sh
> +++ b/ld/emulparams/elf_iamcu.sh
> @@ -21,6 +21,7 @@ IREL_IN_PLT=
> OTHER_PLT_SECTIONS="
> .plt.got ${RELOCATING-0} : { *(.plt.got) }
> "
> +ALL_TEXT_AFTER_RO=yes
>
> # Linux modify the default library search path to first include
> # a 32-bit specific directory.
> diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
> index 747114bc4b4..63e2419184c 100644
> --- a/ld/emulparams/elf_x86_64.sh
> +++ b/ld/emulparams/elf_x86_64.sh
> @@ -37,6 +37,7 @@ OTHER_PLT_SECTIONS="
> "
> OTHER_GOT_RELOC_SECTIONS="
> .rela.tls ${RELOCATING-0} : { *(.rela.tls) }"
> +ALL_TEXT_AFTER_RO=yes
>
> if [ "x${host}" = "x${target}" ]; then
> case " $EMULATION_LIBPATH " in
> diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
> index 8a0efc02c86..2ded3fa3ddd 100644
> --- a/ld/scripttempl/elf.sc
> +++ b/ld/scripttempl/elf.sc
> @@ -82,6 +82,8 @@
> # applied to every symbol definition
> # ALL_TEXT_BEFORE_RO - put all code sections before read-only
> # sections
> +# ALL_TEXT_AFTER_RO - put all code sections after read-only
> +# sections
> #
> # When adding sections, do note that the names of some sections are used
> # when specifying the start address of the next.
> @@ -360,7 +362,11 @@ SHLIB_TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${SHLIB_TEXT_START_ADDR:-
> if test -z "$TINY_READONLY_SECTION"; then
> case "$LD_FLAG" in
> *ro*textonly*)
> - ALL_TEXT_BEFORE_RO=" "
> + if test -n "${ALL_TEXT_AFTER_RO}"; then
> + TEXT_AFTER_RO=" "
> + else
> + ALL_TEXT_BEFORE_RO=" "
> + fi
> SEPARATE_TEXT=" "
> TEXT_SEGMENT_ALIGN=". = ALIGN(${MAXPAGESIZE});"
> ;;
> @@ -1021,7 +1027,7 @@ EOF
>
> #------Early Read Only Data -----------------------------------------------
>
> - if test -z "${ALL_TEXT_BEFORE_RO}"; then
> + if test -n "${TEXT_AFTER_RO}" || test -z "${ALL_TEXT_BEFORE_RO}"; then
> # We are allowed to put R/O sections before code sections.
> # Doing so either puts read only data into the code segment, if the data
> # and code sections are contiguous, or creates a data segment followed by
> @@ -1033,6 +1039,7 @@ EOF
>
> test -n "${SEPARATE_CODE}" || emit_early_ro
> test -n "${NON_ALLOC_DYN}${SEPARATE_CODE}" || emit_dyn
> + test -z "${TEXT_AFTER_RO}" || emit_rodata
>
> # We only need the alignment if we have emitted some sections.
> if test -z "${SEPARATE_CODE}"; then
> @@ -1058,24 +1065,26 @@ EOF
>
> align_text
>
> - #------Read Only Data -----------------------------------------------------
> + if test -z "${TEXT_AFTER_RO}"; then
> + #------Read Only Data ------------------------------------------------
>
> - align_rodata
> + align_rodata
>
> - # If we have not already emitted the early read only data sections then do
> - # so now. Also if the dynamic section has not already been emitted and we
> - # can put it into the data segment, then do that here as well.
> + # If we have not already emitted the early read only data sections then do
> + # so now. Also if the dynamic section has not already been emitted and we
> + # can put it into the data segment, then do that here as well.
>
> - if test -n "${ALL_TEXT_BEFORE_RO}"; then
> - test -n "${SEPARATE_CODE}" || emit_early_ro
> - test -n "${NON_ALLOC_DYN}${SEPARATE_CODE}" || emit_dyn
> - fi
> - test -z "${SEPARATE_CODE}" || emit_early_ro
> - test -z "${SEPARATE_CODE}" || emit_dyn
> + if test -n "${ALL_TEXT_BEFORE_RO}"; then
> + test -n "${SEPARATE_CODE}" || emit_early_ro
> + test -n "${NON_ALLOC_DYN}${SEPARATE_CODE}" || emit_dyn
> + fi
> + test -z "${SEPARATE_CODE}" || emit_early_ro
> + test -z "${SEPARATE_CODE}" || emit_dyn
>
> - # Now emit the rest of the read only data.
> + # Now emit the rest of the read only data.
>
> - emit_rodata
> + emit_rodata
> + fi
>
> #------Read Write Data ----------------------------------------------------
>
> diff --git a/ld/testsuite/ld-elf/pr30907-2.d b/ld/testsuite/ld-elf/pr30907-2.d
> index fed957e760e..f6254d3ab25 100644
> --- a/ld/testsuite/ld-elf/pr30907-2.d
> +++ b/ld/testsuite/ld-elf/pr30907-2.d
> @@ -2,6 +2,7 @@
> #source: pr22393-1.s
> #ld: -shared -z separate-code -z relro --rosegment
> #readelf: -l --wide
> +#notarget: i?86-*-* x86_64-*-*
> #target: *-*-linux-gnu *-*-gnu* arm*-*-uclinuxfdpiceabi
> #xfail: ![check_shared_lib_support]
> #xfail: ![check_relro_support]
> diff --git a/ld/testsuite/ld-elf/pr34003.d b/ld/testsuite/ld-elf/pr34003.d
> new file mode 100644
> index 00000000000..9e04914e647
> --- /dev/null
> +++ b/ld/testsuite/ld-elf/pr34003.d
> @@ -0,0 +1,13 @@
> +#name: --rosegment (has at least one R, one RX and one RW segments)
> +#source: pr22393-1.s
> +#ld: -shared -z separate-code -z relro --rosegment
> +#readelf: -l --wide
> +#target: i?86-*-* x86_64-*-*
> +
> +#...
> +[ ]+LOAD[ ]+0x[0-9a-f x]+R[ ]+0x.*
> +#...
> +[ ]+LOAD[ ]+0x[0-9a-f x]+R E[ ]+0x.*
> +#...
> +[ ]+LOAD[ ]+0x[0-9a-f x]+RW[ ]+0x.*
> +#...
> diff --git a/ld/testsuite/ld-i386/pr32191.d b/ld/testsuite/ld-i386/pr32191.d
> index 8d7838a1311..5558da1b0b8 100644
> --- a/ld/testsuite/ld-i386/pr32191.d
> +++ b/ld/testsuite/ld-i386/pr32191.d
> @@ -4,6 +4,8 @@
> #readelf: -lW
>
> #...
> - +[0-9]+ +\.note\.gnu\.build-id \.text
> + +[0-9]+ +\.note\.gnu\.build-id .*
> + +[0-9]+ +\.text
> +#...
> +[0-9]+ +\..* \.note\.gnu\.property .*
> #pass
> diff --git a/ld/testsuite/ld-x86-64/pr32191-x32.d b/ld/testsuite/ld-x86-64/pr32191-x32.d
> index 19e06a26c11..b574e05f6c9 100644
> --- a/ld/testsuite/ld-x86-64/pr32191-x32.d
> +++ b/ld/testsuite/ld-x86-64/pr32191-x32.d
> @@ -4,6 +4,8 @@
> #readelf: -lW
>
> #...
> - +[0-9]+ +\.note\.gnu\.build-id \.text
> + +[0-9]+ +\.note\.gnu\.build-id .*
> + +[0-9]+ +\.text
> +#...
> +[0-9]+ +\..* \.note\.gnu\.property .*
> #pass
> diff --git a/ld/testsuite/ld-x86-64/pr32191.d b/ld/testsuite/ld-x86-64/pr32191.d
> index 9038ccd9b35..2a0c0339165 100644
> --- a/ld/testsuite/ld-x86-64/pr32191.d
> +++ b/ld/testsuite/ld-x86-64/pr32191.d
> @@ -4,6 +4,8 @@
> #readelf: -lW
>
> #...
> - +[0-9]+ +\.note\.gnu\.build-id \.text
> + +[0-9]+ +\.note\.gnu\.build-id .*
> + +[0-9]+ +\.text
> +#...
> +[0-9]+ +\..* \.note\.gnu\.property .*
> #pass
> --
> 2.53.0
>
--
H.J.
More information about the Binutils
mailing list