[binutils-gdb] elf/x86: Place code after read-only data for --rosegment

"H.J. Lu via Binutils-cvs" <[email protected]>
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=99600a4787910d4b1994b243473a7386dbee641d

commit 99600a4787910d4b1994b243473a7386dbee641d
Author: H.J. Lu <[email protected]>
Date:   Wed Mar 18 12:13:26 2026 -0700

    elf/x86: Place code after read-only data for --rosegment
    
    commit e8e10743f7b207b21a1efb0cc9e42487080db013
    Author: Nick Clifton <[email protected]>
    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
    
            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 <[email protected]>

Diff:
---
 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(-)

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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.