RFC: Three load segments patch (PR 30907) [version 2]

Message ID 874j9y6ufe.fsf@redhat.com
State New
Headers
Series RFC: Three load segments patch (PR 30907) [version 2] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed

Commit Message

Nick Clifton June 12, 2024, 3:40 p.m. UTC
  Hi Guys,

  I have been looking into the file size increase when we link binaries
  with '-z separate-code' enabled.  The problem is that we end up
  creating four load segments with page aligning happening between them.
  For example linking a small hello-world type program gives:

  with: -z noseparate-code  (file size: 8544 bytes)

          File Offset  Virt Addr  FileSize Flags  Align
    LOAD      0         400000      6d4     R E    0x1000 
    LOAD    df8         401df8      228     RW     0x1000

  with: -z separate-code  (file size: 16736 bytes)

          File Offset  Virt Addr  FileSize Flags  Align
    LOAD      0         400000      510     R      0x1000
    LOAD   1000         401000      155     R E    0x1000
    LOAD   2000         402000       dc     R      0x1000
    LOAD   2df8         403df8      228     RW     0x1000

  The increase in size is unfortunate, and a problem for distributions,
  where larger binary sizes equates to larger install images and more
  download bandwidth, and the problem is even more accute for containers.

  So attached is a proposed patch to add an option that combines the two
  read-only segments into one.  It moves the first code segment to the
  start of the file, followed by a read only segment and then a read
  write segment.  Thus we end up with a layout like this:

  with: -z separate-code -z one-rosegment  (file size: 8544 bytes)

          File Offset  Virt Addr  FileSize Flags  Align
    LOAD      0         400000      435     R E    0x1000
    LOAD    435         401435      2d7     R      0x1000
    LOAD    df8         402df8      228     RW     0x1000

  The section mapping looks like this:

     02     .init .plt .text .fini 
     03     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .rodata .eh_frame_hdr .eh_frame 
     04     .init_array .fini_array .dynamic .got .got.plt .data .bss 

  The patch is incomplete.  It does not have any test cases or
  full documentation at the moment, but I wanted to see if I am on the
  right track this time, or if I need to go back to the drawing board
  again. :-)

Cheers
  Nick

PS. In addition to adding the new command line option the patch also
updates the ld/ld.int documentation file, adding descriptions of linker
scripts that were missing before.  It also reorganises the
ld/scripttempl/elf.sc linker script template, making it easier to
understand how the sections are laid out.  (At least that is my
opinion).
  

Comments

Fangrui Song June 12, 2024, 9:01 p.m. UTC | #1
On Wed, Jun 12, 2024 at 8:40 AM Nick Clifton <nickc@redhat.com> wrote:
>
> Hi Guys,
>
>   I have been looking into the file size increase when we link binaries
>   with '-z separate-code' enabled.  The problem is that we end up
>   creating four load segments with page aligning happening between them.
>   For example linking a small hello-world type program gives:
>
>   with: -z noseparate-code  (file size: 8544 bytes)
>
>           File Offset  Virt Addr  FileSize Flags  Align
>     LOAD      0         400000      6d4     R E    0x1000
>     LOAD    df8         401df8      228     RW     0x1000
>
>   with: -z separate-code  (file size: 16736 bytes)
>
>           File Offset  Virt Addr  FileSize Flags  Align
>     LOAD      0         400000      510     R      0x1000
>     LOAD   1000         401000      155     R E    0x1000
>     LOAD   2000         402000       dc     R      0x1000
>     LOAD   2df8         403df8      228     RW     0x1000
>
>   The increase in size is unfortunate, and a problem for distributions,
>   where larger binary sizes equates to larger install images and more
>   download bandwidth, and the problem is even more accute for containers.
>
>   So attached is a proposed patch to add an option that combines the two
>   read-only segments into one.  It moves the first code segment to the
>   start of the file, followed by a read only segment and then a read
>   write segment.  Thus we end up with a layout like this:
>
>   with: -z separate-code -z one-rosegment  (file size: 8544 bytes)
>
>           File Offset  Virt Addr  FileSize Flags  Align
>     LOAD      0         400000      435     R E    0x1000
>     LOAD    435         401435      2d7     R      0x1000
>     LOAD    df8         402df8      228     RW     0x1000
>
>   The section mapping looks like this:
>
>      02     .init .plt .text .fini
>      03     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .rodata .eh_frame_hdr .eh_frame
>      04     .init_array .fini_array .dynamic .got .got.plt .data .bss
>
>   The patch is incomplete.  It does not have any test cases or
>   full documentation at the moment, but I wanted to see if I am on the
>   right track this time, or if I need to go back to the drawing board
>   again. :-)
>
> Cheers
>   Nick
>
> PS. In addition to adding the new command line option the patch also
> updates the ld/ld.int documentation file, adding descriptions of linker
> scripts that were missing before.  It also reorganises the
> ld/scripttempl/elf.sc linker script template, making it easier to
> understand how the sections are laid out.  (At least that is my
> opinion).
>

Hi Nick,

Thanks for working on the size bloat issue. I haven't checked closely,
but the proposed -z one-rosegment probably does something similar to
--rosegment.

My feature requests remain at
https://sourceware.org/pipermail/binutils/2024-June/134541.html

Splitting -z separate-code into --rosegment and -z separate-code (as
suggested in https://sourceware.org/bugzilla/show_bug.cgi?id=30907#c4)
might be useful. Gold introduced --rosegment, which has been adopted
by lld and mold as well.

-z separate-code/noseparate-code is primarily about

. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (.
& (CONSTANT (MAXPAGESIZE) - 1)));
vs
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));

instead of rosegment.
  
Jan Beulich June 13, 2024, 6:10 a.m. UTC | #2
On 12.06.2024 17:40, Nick Clifton wrote:
>   I have been looking into the file size increase when we link binaries
>   with '-z separate-code' enabled.  The problem is that we end up
>   creating four load segments with page aligning happening between them.
>   For example linking a small hello-world type program gives:
> 
>   with: -z noseparate-code  (file size: 8544 bytes)
> 
>           File Offset  Virt Addr  FileSize Flags  Align
>     LOAD      0         400000      6d4     R E    0x1000 
>     LOAD    df8         401df8      228     RW     0x1000
> 
>   with: -z separate-code  (file size: 16736 bytes)
> 
>           File Offset  Virt Addr  FileSize Flags  Align
>     LOAD      0         400000      510     R      0x1000
>     LOAD   1000         401000      155     R E    0x1000
>     LOAD   2000         402000       dc     R      0x1000
>     LOAD   2df8         403df8      228     RW     0x1000
> 
>   The increase in size is unfortunate, and a problem for distributions,
>   where larger binary sizes equates to larger install images and more
>   download bandwidth, and the problem is even more accute for containers.
> 
>   So attached is a proposed patch to add an option that combines the two
>   read-only segments into one.  It moves the first code segment to the
>   start of the file, followed by a read only segment and then a read
>   write segment.  Thus we end up with a layout like this:
> 
>   with: -z separate-code -z one-rosegment  (file size: 8544 bytes)
> 
>           File Offset  Virt Addr  FileSize Flags  Align
>     LOAD      0         400000      435     R E    0x1000
>     LOAD    435         401435      2d7     R      0x1000
>     LOAD    df8         402df8      228     RW     0x1000
> 
>   The section mapping looks like this:
> 
>      02     .init .plt .text .fini 
>      03     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .rodata .eh_frame_hdr .eh_frame 
>      04     .init_array .fini_array .dynamic .got .got.plt .data .bss 
> 
>   The patch is incomplete.  It does not have any test cases or
>   full documentation at the moment, but I wanted to see if I am on the
>   right track this time, or if I need to go back to the drawing board
>   again. :-)

FWIW, the result of your change addresses my earlier concern. (I didn't
look closely at the implementation, though.)

Thanks for the re-work, Jan
  
Nick Clifton June 13, 2024, 2:15 p.m. UTC | #3
Hi Fangrui,

> Thanks for working on the size bloat issue. I haven't checked closely,
> but the proposed -z one-rosegment probably does something similar to
> --rosegment.

Exactly.  I was trying to emulate what that option did.

> My feature requests remain at
> https://sourceware.org/pipermail/binutils/2024-June/134541.html

> Splitting -z separate-code into --rosegment and -z separate-code (as
> suggested in https://sourceware.org/bugzilla/show_bug.cgi?id=30907#c4)
> might be useful. Gold introduced --rosegment, which has been adopted
> by lld and mold as well.

Fair enough.  So I have decided to go ahead and commit my patch, although
I have renamed the option to --rosegment instead of -z one-rosegment.  I
prefer my original name for the option, but being compatible with the other
linkers is more important I feel, so I made the change.

The option is not enabled by default unless the new --enable-rosegment
configure option is used, but at least having it in the code means that
more people than just myself can experiment with it.

Cheers
   Nick
  

Patch

diff --git a/bfd/elf.c b/bfd/elf.c
index 74236a658fd..b0b1e94d16c 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -5335,7 +5335,9 @@  _bfd_elf_map_sections_to_segments (bfd *abfd,
 		 thus not executable, and the first section is
 		 executable then put the file and program headers in
 		 their own PT_LOAD.  */
-	      separate_phdr = true;
+	      if (!info->one_rosegment)
+		separate_phdr = true;
+
 	      if ((((phdr_lma + phdr_size - 1) & addr_mask & -maxpagesize)
 		   == (sections[0]->lma & addr_mask & -maxpagesize)))
 		{
diff --git a/include/bfdlink.h b/include/bfdlink.h
index eac07d78364..015370d268f 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -423,6 +423,9 @@  struct bfd_link_info
   /* TRUE if separate code segment should be created.  */
   unsigned int separate_code: 1;
 
+  /* TRUE if only one read-only, non-code segment should be created.  */
+  unsigned int one_rosegment: 1;
+
   /* Nonzero if .eh_frame_hdr section and PT_GNU_EH_FRAME ELF segment
      should be created.  1 for DWARF2 tables, 2 for compact tables.  */
   unsigned int eh_frame_hdr_type: 2;
diff --git a/ld/aclocal.m4 b/ld/aclocal.m4
index 01c2dc2694d..87090e17ada 100644
--- a/ld/aclocal.m4
+++ b/ld/aclocal.m4
@@ -1185,8 +1185,6 @@  AC_SUBST([am__tar])
 AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
 
-m4_include([../bfd/acinclude.m4])
-m4_include([../bfd/warning.m4])
 m4_include([../config/acx.m4])
 m4_include([../config/bfd64.m4])
 m4_include([../config/depstand.m4])
@@ -1211,6 +1209,8 @@  m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
 m4_include([../config/zstd.m4])
+m4_include([../bfd/acinclude.m4])
+m4_include([../bfd/warning.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/ld/config.in b/ld/config.in
index 52d62f06ff0..c051d397567 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -49,6 +49,10 @@ 
    default. */
 #undef DEFAULT_LD_Z_MARK_PLT
 
+/* Define to 1 if you want to enable -z one-rosegment in ELF linker by
+   default. */
+#undef DEFAULT_LD_Z_ONE_ROSEGMENT
+
 /* Define to 1 if you want to enable -z relro in ELF linker by default. */
 #undef DEFAULT_LD_Z_RELRO
 
diff --git a/ld/configure b/ld/configure
index 9151640ca60..a078a2d0889 100755
--- a/ld/configure
+++ b/ld/configure
@@ -852,6 +852,7 @@  enable_new_dtags
 enable_relro
 enable_textrel_check
 enable_separate_code
+enable_one_rosegment
 enable_mark_plt
 enable_warn_execstack
 enable_error_execstack
@@ -1547,6 +1548,7 @@  Optional Features:
   --enable-textrel-check=[yes|no|warning|error]
                           enable DT_TEXTREL check in ELF linker
   --enable-separate-code  enable -z separate-code in ELF linker by default
+  --enable-one-rosegment  enable -z one-rosegment in ELF linker by default
   --enable-mark-plt       enable -z mark-plt in ELF x86-64 linker by default
   --enable-warn-execstack enable warnings when creating an executable stack
   --enable-error-execstack
@@ -15682,6 +15684,17 @@  esac
 fi
 
 
+# Decide if -z one-rosegment should be enabled in ELF linker by default.
+ac_default_ld_z_one_rosegment=unset
+# Check whether --enable-one-rosegment was given.
+if test "${enable_one_rosegment+set}" = set; then :
+  enableval=$enable_one_rosegment; case "${enableval}" in
+  yes) ac_default_ld_z_one_rosegment=1 ;;
+  no) ac_default_ld_z_one_rosegment=0 ;;
+esac
+fi
+
+
 # Decide if -z mark-plt should be enabled in ELF x86-64 linker by default.
 ac_default_ld_z_mark_plt=unset
 # Check whether --enable-mark-plt was given.
@@ -19381,6 +19394,15 @@  cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+if test "${ac_default_ld_z_one_rosegment}" = unset; then
+  ac_default_ld_z_one_rosegment=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_LD_Z_ONE_ROSEGMENT $ac_default_ld_z_one_rosegment
+_ACEOF
+
+
 if test "${ac_default_ld_z_mark_plt}" = unset; then
   ac_default_ld_z_mark_plt=0
 fi
diff --git a/ld/configure.ac b/ld/configure.ac
index 8ba6cf9edfb..17c28332e55 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -212,6 +212,16 @@  AC_ARG_ENABLE(separate-code,
   no) ac_default_ld_z_separate_code=0 ;;
 esac])
 
+# Decide if -z one-rosegment should be enabled in ELF linker by default.
+ac_default_ld_z_one_rosegment=unset
+AC_ARG_ENABLE(one-rosegment,
+	      AS_HELP_STRING([--enable-one-rosegment],
+	      [enable -z one-rosegment in ELF linker by default]),
+[case "${enableval}" in
+  yes) ac_default_ld_z_one_rosegment=1 ;;
+  no) ac_default_ld_z_one_rosegment=0 ;;
+esac])
+
 # Decide if -z mark-plt should be enabled in ELF x86-64 linker by default.
 ac_default_ld_z_mark_plt=unset
 AC_ARG_ENABLE(mark-plt,
@@ -571,6 +581,13 @@  AC_DEFINE_UNQUOTED(DEFAULT_LD_Z_SEPARATE_CODE,
   $ac_default_ld_z_separate_code,
   [Define to 1 if you want to enable -z separate-code in ELF linker by default.])
 
+if test "${ac_default_ld_z_one_rosegment}" = unset; then
+  ac_default_ld_z_one_rosegment=0
+fi
+AC_DEFINE_UNQUOTED(DEFAULT_LD_Z_ONE_ROSEGMENT,
+  $ac_default_ld_z_one_rosegment,
+  [Define to 1 if you want to enable -z one-rosegment in ELF linker by default.])
+
 if test "${ac_default_ld_z_mark_plt}" = unset; then
   ac_default_ld_z_mark_plt=0
 fi
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index 55a870f7d2d..c56bac53cda 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -93,6 +93,7 @@  EOF
 fi
 fragment <<EOF
   link_info.separate_code = DEFAULT_LD_Z_SEPARATE_CODE;
+  link_info.one_rosegment = DEFAULT_LD_Z_ONE_ROSEGMENT;
   link_info.warn_execstack = DEFAULT_LD_WARN_EXECSTACK;
   link_info.no_warn_rwx_segments = ! DEFAULT_LD_WARN_RWX_SEGMENTS;
   link_info.default_execstack = DEFAULT_LD_EXECSTACK;
@@ -212,151 +213,303 @@  fragment <<EOF
     return
 EOF
 sed $sc ldscripts/${EMULATION_NAME}.xu			>> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_relocatable (&link_info)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xr			>> e${EMULATION_NAME}.c
+
 echo '  ; else if (!config.text_read_only) return'	>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xbn			>> e${EMULATION_NAME}.c
+
 if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ; else
-echo '  ; else if (!config.magic_demand_paged) return'	>> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xn			>> e${EMULATION_NAME}.c
+  echo '  ; else if (!config.magic_demand_paged) return'	>> e${EMULATION_NAME}.c
+  sed $sc ldscripts/${EMULATION_NAME}.xn			>> e${EMULATION_NAME}.c
 fi
+
 if test -n "$GENERATE_PIE_SCRIPT" ; then
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
+
+echo '  ; else if (bfd_link_pie (&link_info)'		>> e${EMULATION_NAME}.c
+echo '             && link_info.combreloc'		>> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code'		>> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'		>> e${EMULATION_NAME}.c
+echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xdwer		>> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_pie (&link_info)'		>> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc'		>> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code'		>> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xdwe		>> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_pie (&link_info)'		>> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc'		>> e${EMULATION_NAME}.c
 echo '             && link_info.relro'			>> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xdw			>> e${EMULATION_NAME}.c
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
+echo '  ; else if (bfd_link_pie (&link_info)'          >> e${EMULATION_NAME}.c
+echo '             && link_info.combreloc'             >> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code'         >> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'         >> e${EMULATION_NAME}.c
+echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xdceor             >> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_pie (&link_info)'          >> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc'             >> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code'         >> e${EMULATION_NAME}.c
 echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xdceo              >> e${EMULATION_NAME}.c
+
 fi
+
+echo '  ; else if (bfd_link_pie (&link_info)'		>> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code'		>> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'		>> e${EMULATION_NAME}.c
+echo '             && link_info.combreloc) return'	>> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xdcer		>> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_pie (&link_info)'		>> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code'		>> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc) return'	>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xdce		>> e${EMULATION_NAME}.c
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
 echo '  ; else if (bfd_link_pie (&link_info)'          >> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc'             >> e${EMULATION_NAME}.c
 echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xdco               >> e${EMULATION_NAME}.c
+
 fi
+
 echo '  ; else if (bfd_link_pie (&link_info)'		>> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc) return'	>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xdc			>> e${EMULATION_NAME}.c
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
+echo '  ; else if (bfd_link_pie (&link_info)'          >> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code'         >> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'         >> e${EMULATION_NAME}.c
+echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xdeor              >> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_pie (&link_info)'          >> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code'         >> e${EMULATION_NAME}.c
 echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xdeo               >> e${EMULATION_NAME}.c
+
 fi
+
 fi
+
+echo '  ; else if (bfd_link_pie (&link_info)'		>> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'	        >> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code) return'	>> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xder		>> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_pie (&link_info)'		>> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code) return'	>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xde			>> e${EMULATION_NAME}.c
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
 echo '  ; else if (bfd_link_pie (&link_info)'          >> e${EMULATION_NAME}.c
 echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xdo                >> e${EMULATION_NAME}.c
+
 fi
+
 echo '  ; else if (bfd_link_pie (&link_info)) return'	>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xd			>> e${EMULATION_NAME}.c
 fi
+
 if test -n "$GENERATE_SHLIB_SCRIPT" ; then
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
+
+echo '  ; else if (bfd_link_dll (&link_info)'		>> e${EMULATION_NAME}.c
+echo '             && link_info.combreloc'		>> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code'		>> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'		>> e${EMULATION_NAME}.c
+echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xswer		>> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_dll (&link_info)'		>> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc'		>> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code'		>> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xswe		>> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_dll (&link_info)'		>> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc'		>> e${EMULATION_NAME}.c
 echo '             && link_info.relro'			>> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xsw			>> e${EMULATION_NAME}.c
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
+echo '  ; else if (bfd_link_dll (&link_info)'          >> e${EMULATION_NAME}.c
+echo '             && link_info.combreloc'             >> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code'         >> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'         >> e${EMULATION_NAME}.c
+echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xsceor             >> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_dll (&link_info)'          >> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc'             >> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code'         >> e${EMULATION_NAME}.c
 echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xsceo              >> e${EMULATION_NAME}.c
+
 fi
+
+echo '  ; else if (bfd_link_dll (&link_info)'		>> e${EMULATION_NAME}.c
+echo '             && link_info.combreloc'		>> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'		>> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code) return'	>> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xscer		>> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_dll (&link_info)'		>> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc'		>> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code) return'	>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xsce			>> e${EMULATION_NAME}.c
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
 echo '  ; else if (bfd_link_dll (&link_info)'          >> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc'             >> e${EMULATION_NAME}.c
 echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xsco               >> e${EMULATION_NAME}.c
+
 fi
+
 echo '  ; else if (bfd_link_dll (&link_info)'		>> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc) return'	>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xsc			>> e${EMULATION_NAME}.c
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
+echo '  ; else if (bfd_link_dll (&link_info)'          >> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code'         >> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'         >> e${EMULATION_NAME}.c
+echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xseor              >> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_dll (&link_info)'          >> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code'         >> e${EMULATION_NAME}.c
 echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xseo               >> e${EMULATION_NAME}.c
+
 fi
+
 fi
+
+echo '  ; else if (bfd_link_dll (&link_info)'		>> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'   	>> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code) return'	>> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xser		>> e${EMULATION_NAME}.c
+
 echo '  ; else if (bfd_link_dll (&link_info)'		>> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code) return'	>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xse			>> e${EMULATION_NAME}.c
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
 echo '  ; else if (bfd_link_dll (&link_info)'          >> e${EMULATION_NAME}.c
 echo '             && link_info.relro) return'         >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xso               >> e${EMULATION_NAME}.c
+
 fi
+
 echo '  ; else if (bfd_link_dll (&link_info)) return'	>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xs			>> e${EMULATION_NAME}.c
+
 fi
+
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
+
 echo '  ; else if (link_info.combreloc'			>> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code'		>> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xwe			>> e${EMULATION_NAME}.c
+
+echo '  ; else if (link_info.combreloc'			>> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code'		>> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'		>> e${EMULATION_NAME}.c
+echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xwer		>> e${EMULATION_NAME}.c
+
 echo '  ; else if (link_info.combreloc'			>> e${EMULATION_NAME}.c
 echo '             && link_info.relro'			>> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xw			>> e${EMULATION_NAME}.c
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
+echo '  ; else if (link_info.combreloc'                 >> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code'		>> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'		>> e${EMULATION_NAME}.c
+echo '             && link_info.relro) return'          >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xceor               >> e${EMULATION_NAME}.c
+
 echo '  ; else if (link_info.combreloc'                 >> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code'		>> e${EMULATION_NAME}.c
 echo '             && link_info.relro) return'          >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xceo                >> e${EMULATION_NAME}.c
+
 fi
+
+echo '  ; else if (link_info.combreloc'			>> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'	        >> e${EMULATION_NAME}.c
+echo '             && link_info.separate_code) return'	>> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xcer		>> e${EMULATION_NAME}.c
+
 echo '  ; else if (link_info.combreloc'			>> e${EMULATION_NAME}.c
 echo '             && link_info.separate_code) return'	>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xce			>> e${EMULATION_NAME}.c
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
 echo '  ; else if (link_info.combreloc'                 >> e${EMULATION_NAME}.c
 echo '             && link_info.relro) return'          >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xco                 >> e${EMULATION_NAME}.c
+
 fi
+
 echo '  ; else if (link_info.combreloc) return'		>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xc			>> e${EMULATION_NAME}.c
+
 fi
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
+echo '  ; else if (link_info.separate_code'             >> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment'          >> e${EMULATION_NAME}.c
+echo '             && link_info.relro) return'          >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xeor                >> e${EMULATION_NAME}.c
+
 echo '  ; else if (link_info.separate_code'             >> e${EMULATION_NAME}.c
 echo '             && link_info.relro) return'          >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xeo                 >> e${EMULATION_NAME}.c
+
 fi
+
+echo '  ; else if (link_info.separate_code'             >> e${EMULATION_NAME}.c
+echo '             && link_info.one_rosegment) return'  >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xer			>> e${EMULATION_NAME}.c
+
 echo '  ; else if (link_info.separate_code) return'     >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xe			>> e${EMULATION_NAME}.c
+
 if test -n "$GENERATE_RELRO_SCRIPT" ; then
+
 echo '  ; else if (link_info.relro) return'             >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xo                  >> e${EMULATION_NAME}.c
+
 fi
+
 echo '  ; else return'					>> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.x			>> e${EMULATION_NAME}.c
 echo '; }'						>> e${EMULATION_NAME}.c
@@ -391,7 +544,12 @@  fragment <<EOF
 	   && (link_info.flags & DF_BIND_NOW))
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xdwe";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xdwer";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xdwe";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xdw";
     }
@@ -403,7 +561,12 @@  fragment <<EOF
 	   && link_info.relro)
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xdceo";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xdceor";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xdceo";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xdco";
     }
@@ -414,7 +577,12 @@  fragment <<EOF
 	   && link_info.combreloc)
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xdce";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xdcer";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xdce";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xdc";
     }
@@ -426,7 +594,12 @@  fragment <<EOF
 	   && link_info.relro)
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xdeo";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xdeor";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xdeo";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xdo";
     }
@@ -436,7 +609,12 @@  fragment <<EOF
   else if (bfd_link_pie (&link_info))
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xde";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xder";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xde";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xd";
     }
@@ -449,7 +627,12 @@  fragment <<EOF
 	   && link_info.relro && (link_info.flags & DF_BIND_NOW))
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xswe";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xswer";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xswe";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xsw";
     }
@@ -461,7 +644,12 @@  fragment <<EOF
 	   && link_info.relro)
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xsceo";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xsceor";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xsceo";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xsco";
     }
@@ -471,7 +659,12 @@  fragment <<EOF
   else if (bfd_link_dll (&link_info) && link_info.combreloc)
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xsce";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xscer";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xsce";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xsc";
     }
@@ -483,7 +676,12 @@  fragment <<EOF
 	   && link_info.relro)
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xseo";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xseor";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xseo";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xso";
     }
@@ -493,7 +691,12 @@  fragment <<EOF
   else if (bfd_link_dll (&link_info))
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xse";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xser";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xse";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xs";
     }
@@ -505,7 +708,12 @@  fragment <<EOF
 	   && (link_info.flags & DF_BIND_NOW))
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xwe";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xwer";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xwe";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xw";
     }
@@ -516,7 +724,12 @@  fragment <<EOF
 	   && link_info.relro)
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xceo";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xceor";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xceo";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xco";
     }
@@ -526,7 +739,12 @@  fragment <<EOF
   else if (link_info.combreloc)
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xce";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xcer";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xce";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xc";
     }
@@ -537,7 +755,12 @@  fragment <<EOF
   else if (link_info.relro)
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xeo";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xeor";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xeo";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.xo";
     }
@@ -547,7 +770,12 @@  fragment <<EOF
   else
     {
       if (link_info.separate_code)
-	return "ldscripts/${EMULATION_NAME}.xe";
+	{
+	  if (link_info.one_rosegment)
+	    return "ldscripts/${EMULATION_NAME}.xer";
+	  else
+	    return "ldscripts/${EMULATION_NAME}.xe";
+	}
       else
 	return "ldscripts/${EMULATION_NAME}.x";
     }
@@ -852,6 +1080,10 @@  fragment <<EOF
 	link_info.separate_code = true;
       else if (strcmp (optarg, "noseparate-code") == 0)
 	link_info.separate_code = false;
+      else if (strcmp (optarg, "one-rosegment") == 0)
+	link_info.one_rosegment = true;
+      else if (strcmp (optarg, "many-rosegments") == 0)
+	link_info.one_rosegment = false;
       else if (strcmp (optarg, "common") == 0)
 	link_info.elf_stt_common = elf_stt_common;
       else if (strcmp (optarg, "nocommon") == 0)
diff --git a/ld/genscripts.sh b/ld/genscripts.sh
index d6ceb3fe4f5..a726b158161 100755
--- a/ld/genscripts.sh
+++ b/ld/genscripts.sh
@@ -64,35 +64,50 @@ 
 # following suffixes might be generated as well:
 #
 # xdwe:   -pie    -z combreloc -z separate-code -z relro -z now
+# xdwer:  -pie    -z combreloc -z separate-code -z relro -z now -z one-rosegment
 # xdw:    -pie    -z combreloc                  -z relro -z now
 # xdceo:  -pie    -z combreloc -z separate-code -z relro
+# xdceor: -pie    -z combreloc -z separate-code -z relro        -z one-rosegment
 # xdce:   -pie    -z combreloc -z separate-code
+# xdcer:  -pie    -z combreloc -z separate-code                 -z one-rosegment
 # xdco:   -pie    -z combreloc                  -z relro
 # xdc:    -pie    -z combreloc
 # xdeo:   -pie                 -z separate-code -z relro
+# xdeor:  -pie                 -z separate-code -z relro        -z one-rosegment
 # xde:    -pie                 -z separate-code
+# xder:   -pie                 -z separate-code                 -z one-rosegment
 # xdo:    -pie                                  -z relro
 # xd:     -pie
 #
 # xswe:   -shared -z combreloc -z separate-code -z relro -z now
+# xswer:  -shared -z combreloc -z separate-code -z relro -z now -z one-rosegment
 # xsw:    -shared -z combreloc                  -z relro -z now
 # xsceo:  -shared -z combreloc -z separate-code -z relro
+# xsceor: -shared -z combreloc -z separate-code -z relro        -z one-rosegment
 # xsce:   -shared -z combreloc -z separate-code
+# xscer:  -shared -z combreloc -z separate-code                 -z one-rosegment
 # xsco:   -shared -z combreloc                  -z relro
 # xsc:    -shared -z combreloc
 # xseo:   -shared              -z separate-code -z relro
+# xseor:  -shared              -z separate-code -z relro        -z one-rosegment
 # xse:    -shared              -z separate-code
+# xser:   -shared              -z separate-code                 -z one-rosegment
 # xso:    -shared                               -z relro
 # xs:     -shared
 #
-# xwe:            -z combreloc -z separate-code -z relro -z now
+# xwe:            -z combreloc -z separate-code -z relro -z now -z one-rosegment
+# xwer:           -z combreloc -z separate-code -z relro -z now
 # xw:             -z combreloc                  -z relro -z now
 # xceo:           -z combreloc -z separate-code -z relro
+# xceor:          -z combreloc -z separate-code -z relro        -z one-rosegment
 # xce:            -z combreloc -z separate-code
+# xcer:           -z combreloc -z separate-code                 -z one-rosegment
 # xco:            -z combreloc                  -z relro
 # xc:             -z combreloc
 # xeo:                         -z separate-code -z relro
+# xeor:                        -z separate-code -z relro        -z one-rosegment
 # xe:                          -z separate-code
+# xer:                         -z separate-code                 -z one-rosegment
 # xo:                                           -z relro
 #
 #
@@ -295,6 +310,8 @@  DATA_ALIGNMENT_N="${DATA_ALIGNMENT_N-${DATA_ALIGNMENT-.}}"
 DATA_ALIGNMENT_r="${DATA_ALIGNMENT_r-${DATA_ALIGNMENT-}}"
 DATA_ALIGNMENT_u="${DATA_ALIGNMENT_u-${DATA_ALIGNMENT_r}}"
 
+# Create scripts using different settings of the LD_FLAG variable
+
 LD_FLAG=r
 DATA_ALIGNMENT=${DATA_ALIGNMENT_r}
 DEFAULT_DATA_ALIGNMENT="ALIGN(${SEGMENT_SIZE})"
@@ -325,20 +342,36 @@  LD_FLAG=textonly
   source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
 ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xe
 
+LD_FLAG=rotextonly
+( echo "/* Script for -z separate-code -z one-rosegment */"
+  source_sh ${CUSTOMIZER_SCRIPT}
+  source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xer
+
 if test -n "$GENERATE_RELRO_SCRIPT"; then
-    LD_FLAG=
     RELRO=" "
+
+    LD_FLAG=
     ( echo "/* Script for -z relro */"
       source_sh ${CUSTOMIZER_SCRIPT}
       source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xo
+
     LD_FLAG=textonly
     ( echo "/* Script for -z separate-code -z relro */"
       source_sh ${CUSTOMIZER_SCRIPT}
       source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xeo
+
+    LD_FLAG=rotextonly
+    ( echo "/* Script for -z separate-code -z relro -z one-rosegment */"
+      source_sh ${CUSTOMIZER_SCRIPT}
+      source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+    ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xeor
+
     unset RELRO
 fi
+
 LD_FLAG=n
 DATA_ALIGNMENT=${DATA_ALIGNMENT_n}
 ( echo "/* Script for -n */"
@@ -362,6 +395,7 @@  if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
     source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
   ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xc
   rm -f ${COMBRELOC}
+  
   LD_FLAG=ctextonly
   COMBRELOC=ldscripts/${EMULATION_NAME}.xce.tmp
   ( echo "/* Script for -z combreloc -z separate-code */"
@@ -369,7 +403,17 @@  if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
     source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
   ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xce
   rm -f ${COMBRELOC}
+
+  LD_FLAG=roctextonly
+  COMBRELOC=ldscripts/${EMULATION_NAME}.xcer.tmp
+  ( echo "/* Script for -z combreloc -z separate-code -z one-rosegment */"
+    source_sh ${CUSTOMIZER_SCRIPT}
+    source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+  ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xcer
+  rm -f ${COMBRELOC}
+
   RELRO_NOW=" "
+
   LD_FLAG=w
   COMBRELOC=ldscripts/${EMULATION_NAME}.xw.tmp
   ( echo "/* Script for -z combreloc -z relro -z now */"
@@ -377,6 +421,7 @@  if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
     source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
   ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xw
   rm -f ${COMBRELOC}
+
   LD_FLAG=wtextonly
   COMBRELOC=ldscripts/${EMULATION_NAME}.xwe.tmp
   ( echo "/* Script for -z combreloc -z separate-code -z relro -z now */"
@@ -385,16 +430,29 @@  if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
   ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xwe
   rm -f ${COMBRELOC}
   COMBRELOC=
+
+  LD_FLAG=rowtextonly
+  COMBRELOC=ldscripts/${EMULATION_NAME}.xwer.tmp
+  ( echo "/* Script for -z combreloc -z separate-code -z relro -z now -z one-rosegment */"
+    source_sh ${CUSTOMIZER_SCRIPT}
+    source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+  ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xwer
+  rm -f ${COMBRELOC}
+  COMBRELOC=
+
   unset RELRO_NOW
+
   if test -n "$GENERATE_RELRO_SCRIPT"; then
-      LD_FLAG=c
       RELRO=" "
+
+      LD_FLAG=c
       COMBRELOC=ldscripts/${EMULATION_NAME}.xco.tmp
       ( echo "/* Script for -z combreloc -z relro */"
 	source_sh ${CUSTOMIZER_SCRIPT}
 	source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
       ) | sed -e '/^ *$/d;s/[    ]*$//' > ldscripts/${EMULATION_NAME}.xco
       rm -f ${COMBRELOC}
+
       LD_FLAG=ctextonly
       COMBRELOC=ldscripts/${EMULATION_NAME}.xceo.tmp
       ( echo "/* Script for -z combreloc -z separate-code -z relro */"
@@ -403,38 +461,66 @@  if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
       ) | sed -e '/^ *$/d;s/[    ]*$//' > ldscripts/${EMULATION_NAME}.xceo
       rm -f ${COMBRELOC}
       COMBRELOC=
+
+      LD_FLAG=roctextonly
+      COMBRELOC=ldscripts/${EMULATION_NAME}.xceor.tmp
+      ( echo "/* Script for -z combreloc -z separate-code -z relro -z one-rosegment */"
+	source_sh ${CUSTOMIZER_SCRIPT}
+	source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+      ) | sed -e '/^ *$/d;s/[    ]*$//' > ldscripts/${EMULATION_NAME}.xceor
+      rm -f ${COMBRELOC}
+      COMBRELOC=
+
       unset RELRO
   fi
 fi
 
 if test -n "$GENERATE_SHLIB_SCRIPT"; then
-  DATA_ALIGNMENT=${DATA_ALIGNMENT_s-${DATA_ALIGNMENT_}}
   CREATE_SHLIB=" "
+  DATA_ALIGNMENT=${DATA_ALIGNMENT_s-${DATA_ALIGNMENT_}}
+
   LD_FLAG=shared
   ( echo "/* Script for -shared */"
     source_sh ${CUSTOMIZER_SCRIPT}
     source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
   ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xs
+
   LD_FLAG=sharedtextonly
   ( echo "/* Script for -shared -z separate-code */"
     source_sh ${CUSTOMIZER_SCRIPT}
     source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
   ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xse
 
+  LD_FLAG=rosharedtextonly
+  ( echo "/* Script for -shared -z separate-code -z one-rosegment */"
+    source_sh ${CUSTOMIZER_SCRIPT}
+    source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+  ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xser
+
   if test -n "$GENERATE_RELRO_SCRIPT"; then
       RELRO=" "
+
       LD_FLAG=shared
       ( echo "/* Script for -shared -z relro */"
 	source_sh ${CUSTOMIZER_SCRIPT}
 	source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
       ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xso
+
       LD_FLAG=sharedtextonly
       ( echo "/* Script for -shared -z separate-code -z relro */"
 	source_sh ${CUSTOMIZER_SCRIPT}
 	source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
       ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xseo
+
+      LD_FLAG=rosharedtextonly
+      ( echo "/* Script for -shared -z separate-code -z relro -z one-rosegment */"
+	source_sh ${CUSTOMIZER_SCRIPT}
+	source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+      ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xseor
+
       unset RELRO
   fi
+
   if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
     DATA_ALIGNMENT=${DATA_ALIGNMENT_sc-${DATA_ALIGNMENT}}
     LD_FLAG=cshared
@@ -444,6 +530,7 @@  if test -n "$GENERATE_SHLIB_SCRIPT"; then
       source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xsc
     rm -f ${COMBRELOC}
+
     LD_FLAG=csharedtextonly
     COMBRELOC=ldscripts/${EMULATION_NAME}.xsce.tmp
     ( echo "/* Script for -shared -z combreloc -z separate-code */"
@@ -451,7 +538,17 @@  if test -n "$GENERATE_SHLIB_SCRIPT"; then
       source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xsce
     rm -f ${COMBRELOC}
+
+    LD_FLAG=rocsharedtextonly
+    COMBRELOC=ldscripts/${EMULATION_NAME}.xscer.tmp
+    ( echo "/* Script for -shared -z combreloc -z separate-code -z one-rosegment */"
+      source_sh ${CUSTOMIZER_SCRIPT}
+      source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+    ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xscer
+    rm -f ${COMBRELOC}
+
     RELRO_NOW=" "
+
     LD_FLAG=wshared
     COMBRELOC=ldscripts/${EMULATION_NAME}.xsw.tmp
     ( echo "/* Script for -shared -z combreloc -z relro -z now */"
@@ -459,6 +556,7 @@  if test -n "$GENERATE_SHLIB_SCRIPT"; then
       source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xsw
     rm -f ${COMBRELOC}
+
     LD_FLAG=wsharedtextonly
     COMBRELOC=ldscripts/${EMULATION_NAME}.xswe.tmp
     ( echo "/* Script for -shared -z combreloc -z separate-code -z relro -z now */"
@@ -466,17 +564,28 @@  if test -n "$GENERATE_SHLIB_SCRIPT"; then
       source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xswe
     rm -f ${COMBRELOC}
+
+    LD_FLAG=rowsharedtextonly
+    COMBRELOC=ldscripts/${EMULATION_NAME}.xswe.tmp
+    ( echo "/* Script for -shared -z combreloc -z separate-code -z relro -z now -z one-rosegment */"
+      source_sh ${CUSTOMIZER_SCRIPT}
+      source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+    ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xswer
+    rm -f ${COMBRELOC}
+
     unset RELRO_NOW
 
     if test -n "$GENERATE_RELRO_SCRIPT"; then
-	LD_FLAG=wshared
 	RELRO=" "
+
+	LD_FLAG=wshared
 	COMBRELOC=ldscripts/${EMULATION_NAME}.xsco.tmp
 	( echo "/* Script for -shared -z combreloc -z relro */"
 	  source_sh ${CUSTOMIZER_SCRIPT}
 	  source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
 	) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xsco
 	rm -f ${COMBRELOC}
+
 	LD_FLAG=wsharedtextonly
 	COMBRELOC=ldscripts/${EMULATION_NAME}.xsceo.tmp
 	( echo "/* Script for -shared -z combreloc -z separate-code -z relro */"
@@ -484,40 +593,70 @@  if test -n "$GENERATE_SHLIB_SCRIPT"; then
 	  source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
 	) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xsceo
 	rm -f ${COMBRELOC}
+
+	LD_FLAG=rowsharedtextonly
+	COMBRELOC=ldscripts/${EMULATION_NAME}.xsceor.tmp
+	( echo "/* Script for -shared -z combreloc -z separate-code -z relro -z one-rosegment */"
+	  source_sh ${CUSTOMIZER_SCRIPT}
+	  source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+	) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xsceor
+	rm -f ${COMBRELOC}
+
 	unset RELRO
     fi
+
     COMBRELOC=
   fi
+
   unset CREATE_SHLIB
 fi
 
 if test -n "$GENERATE_PIE_SCRIPT"; then
-  DATA_ALIGNMENT=${DATA_ALIGNMENT_s-${DATA_ALIGNMENT_}}
   CREATE_PIE=" "
+
+  DATA_ALIGNMENT=${DATA_ALIGNMENT_s-${DATA_ALIGNMENT_}}
   LD_FLAG=pie
   ( echo "/* Script for -pie */"
     source_sh ${CUSTOMIZER_SCRIPT}
     source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
   ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xd
+
   LD_FLAG=pietextonly
   ( echo "/* Script for -pie -z separate-code */"
     source_sh ${CUSTOMIZER_SCRIPT}
     source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
   ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xde
+
+  LD_FLAG=ropietextonly
+  ( echo "/* Script for -pie -z separate-code -z one-rosegment */"
+    source_sh ${CUSTOMIZER_SCRIPT}
+    source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+  ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xder
+
   if test -n "$GENERATE_RELRO_SCRIPT"; then
       RELRO=" "
+
       LD_FLAG=pie
       ( echo "/* Script for -pie -z relro */"
 	source_sh ${CUSTOMIZER_SCRIPT}
 	source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
       ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdo
+
       LD_FLAG=pietextonly
       ( echo "/* Script for -pie -z separate-code -z relro */"
 	source_sh ${CUSTOMIZER_SCRIPT}
 	source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
       ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdeo
+
+      LD_FLAG=ropietextonly
+      ( echo "/* Script for -pie -z separate-code -z relro -z one-rosegment */"
+	source_sh ${CUSTOMIZER_SCRIPT}
+	source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+      ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdeor
+
       unset RELRO
   fi
+
   if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
     DATA_ALIGNMENT=${DATA_ALIGNMENT_sc-${DATA_ALIGNMENT}}
     COMBRELOC=ldscripts/${EMULATION_NAME}.xdc.tmp
@@ -527,6 +666,7 @@  if test -n "$GENERATE_PIE_SCRIPT"; then
       source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdc
     rm -f ${COMBRELOC}
+
     LD_FLAG=cpietextonly
     COMBRELOC=ldscripts/${EMULATION_NAME}.xdce.tmp
     ( echo "/* Script for -pie -z combreloc -z separate-code */"
@@ -534,7 +674,17 @@  if test -n "$GENERATE_PIE_SCRIPT"; then
       source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdce
     rm -f ${COMBRELOC}
+
+    LD_FLAG=rocpietextonly
+    COMBRELOC=ldscripts/${EMULATION_NAME}.xdcer.tmp
+    ( echo "/* Script for -pie -z combreloc -z separate-code -z one-rosegment */"
+      source_sh ${CUSTOMIZER_SCRIPT}
+      source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+    ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdcer
+    rm -f ${COMBRELOC}
+
     RELRO_NOW=" "
+
     LD_FLAG=wpie
     COMBRELOC=ldscripts/${EMULATION_NAME}.xdw.tmp
     ( echo "/* Script for -pie -z combreloc -z relro -z now */"
@@ -542,6 +692,7 @@  if test -n "$GENERATE_PIE_SCRIPT"; then
       source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdw
     rm -f ${COMBRELOC}
+
     LD_FLAG=wpietextonly
     COMBRELOC=ldscripts/${EMULATION_NAME}.xdwe.tmp
     ( echo "/* Script for -pie -z combreloc -z separate-code -z relro -z now */"
@@ -549,17 +700,28 @@  if test -n "$GENERATE_PIE_SCRIPT"; then
       source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdwe
     rm -f ${COMBRELOC}
+
+    LD_FLAG=rowpietextonly
+    COMBRELOC=ldscripts/${EMULATION_NAME}.xdwer.tmp
+    ( echo "/* Script for -pie -z combreloc -z separate-code -z relro -z now -z one-rosegment */"
+      source_sh ${CUSTOMIZER_SCRIPT}
+      source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+    ) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdwer
+    rm -f ${COMBRELOC}
+
     unset RELRO_NOW
 
     if test -n "$GENERATE_RELRO_SCRIPT"; then
-	LD_FLAG=wpie
 	RELRO=" "
+
+	LD_FLAG=wpie
 	COMBRELOC=ldscripts/${EMULATION_NAME}.xdco.tmp
 	( echo "/* Script for -pie -z combreloc -z relro */"
 	  source_sh ${CUSTOMIZER_SCRIPT}
 	  source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
 	) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdco
 	rm -f ${COMBRELOC}
+
 	LD_FLAG=wpietextonly
 	COMBRELOC=ldscripts/${EMULATION_NAME}.xdceo.tmp
 	( echo "/* Script for -pie -z combreloc -z separate-code -z relro */"
@@ -568,10 +730,20 @@  if test -n "$GENERATE_PIE_SCRIPT"; then
 	) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdceo
 	rm -f ${COMBRELOC}
 
+	LD_FLAG=rowpietextonly
+	COMBRELOC=ldscripts/${EMULATION_NAME}.xdceor.tmp
+	( echo "/* Script for -pie -z combreloc -z separate-code -z relro -z one-rosegment */"
+	  source_sh ${CUSTOMIZER_SCRIPT}
+	  source_sh ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+	) | sed -e '/^ *$/d;s/[	 ]*$//' > ldscripts/${EMULATION_NAME}.xdceor
+	rm -f ${COMBRELOC}
+
 	unset RELRO
     fi
+
     COMBRELOC=
   fi
+
   unset CREATE_PIE
 fi
 
diff --git a/ld/ld.texi b/ld/ld.texi
index ef3706fa7ac..fa766dcac25 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1599,6 +1599,12 @@  specifies a memory segment that should contain only instructions and must
 be in wholly disjoint pages from any other data.  Don't create separate
 code @code{PT_LOAD} segment if @samp{noseparate-code} is used.
 
+@item one-rosegment
+@itemx many-rosegments
+Attempt to ensure that only a single read-only, non-code segment is
+created.  Useful if used in conjunction with the @option{separate-code}
+option.
+
 @item shstk
 Generate GNU_PROPERTY_X86_FEATURE_1_SHSTK in .note.gnu.property section
 to indicate compatibility with Intel Shadow Stack.  Supported for
diff --git a/ld/ldint.texi b/ld/ldint.texi
index 2792a38901a..5549f50908d 100644
--- a/ld/ldint.texi
+++ b/ld/ldint.texi
@@ -252,18 +252,23 @@  Here is the list of values assigned to @code{LD_FLAG}.
 @item (empty)
 The script generated is used by default (when none of the following
 cases apply).  The output has an extension of @file{.x}.
+
 @item n
 The script generated is used when the linker is invoked with the
 @code{-n} option.  The output has an extension of @file{.xn}.
+
 @item N
 The script generated is used when the linker is invoked with the
 @code{-N} option.  The output has an extension of @file{.xbn}.
+
 @item r
 The script generated is used when the linker is invoked with the
 @code{-r} option.  The output has an extension of @file{.xr}.
+
 @item u
 The script generated is used when the linker is invoked with the
 @code{-Ur} option.  The output has an extension of @file{.xu}.
+
 @item shared
 The @file{scripttempl} script is only invoked with @code{LD_FLAG} set to
 this value if @code{GENERATE_SHLIB_SCRIPT} is defined in the
@@ -271,14 +276,15 @@  this value if @code{GENERATE_SHLIB_SCRIPT} is defined in the
 this script at the appropriate time, normally when the linker is invoked
 with the @code{-shared} option.  The output has an extension of
 @file{.xs}.
+
 @item c
 The @file{scripttempl} script is only invoked with @code{LD_FLAG} set to
 this value if @code{GENERATE_COMBRELOC_SCRIPT} is defined in the
 @file{emulparams} file or if @code{SCRIPT_NAME} is @code{elf}. The
 @file{emultempl} script must arrange to use this script at the appropriate
 time, normally when the linker is invoked with the @code{-z combreloc}
-option.  The output has an extension of
-@file{.xc}.
+option.  The output has an extension of @file{.xc}.
+
 @item cshared
 The @file{scripttempl} script is only invoked with @code{LD_FLAG} set to
 this value if @code{GENERATE_COMBRELOC_SCRIPT} is defined in the
@@ -287,6 +293,62 @@  this value if @code{GENERATE_COMBRELOC_SCRIPT} is defined in the
 The @file{emultempl} script must arrange to use this script at the
 appropriate time, normally when the linker is invoked with the @code{-shared
 -z combreloc} option.  The output has an extension of @file{.xsc}.
+
+@item wshared
+Like @emph{cshared} but in addition to needing the @option{-shared}
+and @option {-z combreloc} options, it also needs the
+@option{-z relro} option.  If the @option{-z now} option is also used
+then the output has an extension of @file{.xsw}, otherwise it is
+@file{.xsco}.
+
+@item pie
+The @file{scripttempl} script is only invoked with @code{LD_FLAG} set to
+this value if @code{GENERATE_PIE_SCRIPT} is defined in the
+@file{emulparams} file.  The @file{emultempl} script must arrange to use
+this script at the appropriate time, normally when the linker is invoked
+with the @code{-pie} option.  The output has an extension of
+@file{.xd}.
+
+In addition if the @file{scripttempl} script is also invoked with
+@code{GENERATE_RELRO_SCRIPT} defined then a second script is created
+with an extension of @file{.xdo} to match the @option{-pie} and
+@option{-z relro} options.
+
+@item cpie
+Like @code{pie} but this version is used when the @file{scripttempl}
+script is invoked with both @code{GENERATE_PIE_SCRIPT} and
+@code{GENERATE_COMBRELOC_SCRIPT} defined.  The @file{emultempl} script
+must arrange to use this script at the appropriate time, normally when
+the linker is invoked with the @code{-pie} and @option{-z combreloc}
+options.  The output has an extension of @file{.xdc}.
+
+@item wpie
+Like @code{cpie}, but in addition the @option{-z relro} and
+@option{-z now} options need to be defined.  The output has an
+extension of @file{.xdw}.
+
+@item textonly
+@item pietextonly
+@item cpietextonly
+@item wpietextonly
+
+@item ctextonly
+@item wtextonly
+@item sharedtextonly
+@item csharedtextonly
+@item wsharedtextonly
+
+@item rotextonly
+@item roctextonly
+@item rowtextonly
+@item rosharedtextonly
+@item rocsharedtextonly
+@item rowsharedtextonly
+@item ropietextonly
+@item rocpietextonly
+@item rowpietextonly
+
+
 @item auto_import
 The @file{scripttempl} script is only invoked with @code{LD_FLAG} set to
 this value if @code{GENERATE_AUTO_IMPORT_SCRIPT} is defined in the
@@ -294,8 +356,10 @@  this value if @code{GENERATE_AUTO_IMPORT_SCRIPT} is defined in the
 use this script at the appropriate time, normally when the linker is
 invoked with the @code{--enable-auto-import} option.  The output has
 an extension of @file{.xa}.
+
 @end table
 
+
 Besides the shell variables set by the @file{emulparams} script, and the
 @code{LD_FLAG} variable, the @file{genscripts.sh} script will set
 certain variables for each run of the @file{scripttempl} script.
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 4125d849f2c..80870f61c38 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -2233,6 +2233,17 @@  elf_shlib_list_options (FILE *file)
   -z separate-code            Create separate code program header\n"));
   fprintf (file, _("\
   -z noseparate-code          Don't create separate code program header (default)\n"));
+#endif
+#if DEFAULT_LD_Z_ONE_ROSEGMENT
+  fprintf (file, _("\
+  -z one-rosegment            Create a single read-only, non-code segment (default)\n"));
+  fprintf (file, _("\
+  -z many-rosegments          Allow multiple read-only, non-code segments\n"));
+#else
+  fprintf (file, _("\
+  -z one-rosegment            Create a single read-only, non-code segment\n"));
+  fprintf (file, _("\
+  -z many-rosegments          Allow multiple read-only, non-code segments (default)\n"));
 #endif
   fprintf (file, _("\
   -z common                   Generate common symbols with STT_COMMON type\n"));
diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
index d5022fa502f..f1a61e7bcee 100644
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -80,6 +80,8 @@ 
 #		for standard sections, without initial "." or suffixes.
 #       SYMBOL_ABI_ALIGNMENT - minimum alignment in bytes which needs to be
 #               applied to every symbol definition
+#       ALL_TEXT_BEFORE_RO - put all code sections before read-only
+#               sections
 #
 # When adding sections, do note that the names of some sections are used
 # when specifying the start address of the next.
@@ -367,6 +369,11 @@  SHLIB_TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${SHLIB_TEXT_START_ADDR:-
 # between .plt and .text.
 if test -z "$TINY_READONLY_SECTION"; then
   case "$LD_FLAG" in
+    *ro*textonly*)
+      ALL_TEXT_BEFORE_RO=" "
+      SEPARATE_TEXT=" "
+      TEXT_SEGMENT_ALIGN=
+      ;;
     *textonly*)
       SEPARATE_TEXT=" "
       TEXT_SEGMENT_ALIGN=". = ALIGN(${MAXPAGESIZE});"
@@ -387,6 +394,11 @@  else
    test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR}"
 fi
 
+# ===========================================================================
+# Functions for generating parts of the linker script
+
+emit_header()
+{
 cat <<EOF
 /* Copyright (C) 2014-2024 Free Software Foundation, Inc.
 
@@ -406,14 +418,8 @@  ${RELOCATING- /* For some reason, the Solaris linker makes bad executables
   if gld -r is used and the intermediate file has sections starting
   at non-zero addresses.  Could be a Solaris ld bug, could be a GNU ld
   bug.  But for now assigning the zero vmas works.  */}
-
-SECTIONS
-{
-  ${RELOCATING+${SEPARATE_TEXT-/* Read-only sections, merged into text segment: */}}
-  ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+PROVIDE (__executable_start = ${TEXT_START_ADDR}); . = ${TEXT_BASE_ADDRESS};}}}
-  ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR}${SIZEOF_HEADERS_CODE};}}
-  ${CREATE_PIE+${RELOCATING+PROVIDE (__executable_start = ${SHLIB_TEXT_START_ADDR}); . = ${SHLIB_TEXT_START_ADDR}${SIZEOF_HEADERS_CODE};}}
 EOF
+}
 
 emit_early_ro()
 {
@@ -423,10 +429,21 @@  emit_early_ro()
 EOF
 }
 
-test -n "${SEPARATE_CODE}" || emit_early_ro
+emit_executable_start()
+{
+cat <<EOF
+  ${RELOCATING+${SEPARATE_TEXT-/* Read-only sections, merged into text segment: */}}
+  ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+PROVIDE (__executable_start = ${TEXT_START_ADDR}); . = ${TEXT_BASE_ADDRESS};}}}
+  ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR}${SIZEOF_HEADERS_CODE};}}
+  ${CREATE_PIE+${RELOCATING+PROVIDE (__executable_start = ${SHLIB_TEXT_START_ADDR}); . = ${SHLIB_TEXT_START_ADDR}${SIZEOF_HEADERS_CODE};}}
+EOF
+}
 
+emit_dyn()
+{
 test -n "${RELOCATING+0}" || unset NON_ALLOC_DYN
 test -z "${NON_ALLOC_DYN}" || TEXT_DYNAMIC=
+
 cat > ldscripts/dyntmp.$$ <<EOF
   ${TEXT_DYNAMIC+${DYNAMIC}}
   .hash         ${RELOCATING-0} : { *(.hash) }
@@ -443,6 +460,7 @@  if [ "x$COMBRELOC" = x ]; then
 else
   COMBRELOCCAT="cat > $COMBRELOC"
 fi
+
 eval $COMBRELOCCAT <<EOF
   ${INITIAL_RELOC_SECTIONS}
   .rel.init     ${RELOCATING-0} : { *(.rel.init) }
@@ -518,8 +536,6 @@  cat >> ldscripts/dyntmp.$$ <<EOF
   ${OTHER_PLT_RELOC_SECTIONS}
 EOF
 
-emit_dyn()
-{
   if test -z "${NO_REL_RELOCS}${NO_RELA_RELOCS}"; then
     cat ldscripts/dyntmp.$$
   else
@@ -530,17 +546,24 @@  emit_dyn()
       sed -e '/^[	 ]*\.rel\.[^}]*$/,/}/d;/^[	 ]*\.rel\./d;/__rel_iplt_/d' ldscripts/dyntmp.$$
     fi
   fi
+  
   rm -f ldscripts/dyntmp.$$
+  
   if test -n "${HAVE_DT_RELR}"; then
     echo "  .relr.dyn : { *(.relr.dyn) }"
   fi
 }
 
-test -n "${NON_ALLOC_DYN}${SEPARATE_CODE}" || emit_dyn
-
+align_text()
+{
 cat <<EOF
   ${RELOCATING+${TEXT_SEGMENT_ALIGN}}
+EOF
+}
 
+emit_text()
+{
+cat <<EOF
   .init         ${RELOCATING-0}${RELOCATING+${INIT_ADDR}} :
   {
     ${RELOCATING+${INIT_START}}
@@ -549,7 +572,9 @@  cat <<EOF
   } ${FILL}
 
   ${TEXT_PLT+${PLT_NEXT_DATA-${PLT} ${OTHER_PLT_SECTIONS}}}
+  
   ${TINY_READONLY_SECTION}
+  
   .text         ${RELOCATING-0} :
   {
     ${RELOCATING+${TEXT_START_SYMBOLS}}
@@ -563,19 +588,25 @@  cat <<EOF
     *(.gnu.warning)
     ${RELOCATING+${OTHER_TEXT_SECTIONS}}
   } ${FILL}
+  
   .fini         ${RELOCATING-0}${RELOCATING+${FINI_ADDR}} :
   {
     ${RELOCATING+${FINI_START}}
     KEEP (*(SORT_NONE(.fini)))
     ${RELOCATING+${FINI_END}}
   } ${FILL}
+  
   ${RELOCATING+${ETEXT_LAST_IN_RODATA_SEGMENT-PROVIDE (__${ETEXT_NAME} = .);}}
   ${RELOCATING+${ETEXT_LAST_IN_RODATA_SEGMENT-PROVIDE (_${ETEXT_NAME} = .);}}
   ${RELOCATING+${ETEXT_LAST_IN_RODATA_SEGMENT-PROVIDE (${ETEXT_NAME} = .);}}
   ${RELOCATING+${TEXT_SEGMENT_ALIGN}}
 EOF
+}
 
+align_rodata()
+{
 if test -n "${SEPARATE_CODE}${SEPARATE_TEXT}"; then
+
   if test -n "${RODATA_ADDR}"; then
     RODATA_ADDR="\
 SEGMENT_START(\"rodata-segment\", ${RODATA_ADDR}) + SIZEOF_HEADERS"
@@ -583,6 +614,7 @@  SEGMENT_START(\"rodata-segment\", ${RODATA_ADDR}) + SIZEOF_HEADERS"
     RODATA_ADDR="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))"
     RODATA_ADDR="SEGMENT_START(\"rodata-segment\", ${RODATA_ADDR})"
   fi
+  
   if test -n "${SHLIB_RODATA_ADDR}"; then
     SHLIB_RODATA_ADDR="\
 SEGMENT_START(\"rodata-segment\", ${SHLIB_RODATA_ADDR}) + SIZEOF_HEADERS"
@@ -590,6 +622,7 @@  SEGMENT_START(\"rodata-segment\", ${SHLIB_RODATA_ADDR}) + SIZEOF_HEADERS"
     SHLIB_RODATA_ADDR="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))"
     SHLIB_RODATA_ADDR="SEGMENT_START(\"rodata-segment\", ${SHLIB_RODATA_ADDR})"
   fi
+  
   cat <<EOF
   ${RELOCATING+/* Adjust the address for the rodata segment.  We want to adjust up to
      the same address within the page on the next page up.  */
@@ -597,12 +630,11 @@  SEGMENT_START(\"rodata-segment\", ${SHLIB_RODATA_ADDR}) + SIZEOF_HEADERS"
   ${CREATE_SHLIB+. = ${SHLIB_RODATA_ADDR};}
   ${CREATE_PIE+. = ${SHLIB_RODATA_ADDR};}}
 EOF
-  if test -n "${SEPARATE_CODE}"; then
-    emit_early_ro
-    emit_dyn
-  fi
 fi
+}
 
+emit_rodata()
+{
 cat <<EOF
   ${WRITABLE_RODATA-${RODATA}}
   .${RODATA_NAME}1      ${RELOCATING-0} : { *(.${RODATA_NAME}1) }
@@ -621,7 +653,12 @@  cat <<EOF
   ${RELOCATING+${ETEXT_LAST_IN_RODATA_SEGMENT+PROVIDE (__${ETEXT_NAME} = .);}}
   ${RELOCATING+${ETEXT_LAST_IN_RODATA_SEGMENT+PROVIDE (_${ETEXT_NAME} = .);}}
   ${RELOCATING+${ETEXT_LAST_IN_RODATA_SEGMENT+PROVIDE (${ETEXT_NAME} = .);}}
+EOF
+}
 
+emit_data()
+{
+cat <<EOF
   ${RELOCATING+/* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */}
   ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+. = ${DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}}
@@ -712,7 +749,10 @@  cat <<EOF
   ${NOINIT}
   ${RELOCATING+. = ALIGN(${ALIGNMENT});}
 EOF
+}
 
+emit_large_data()
+{
 LARGE_DATA_ADDR=". = SEGMENT_START(\"ldata-segment\", ${LARGE_DATA_ADDR-.});"
 SHLIB_LARGE_DATA_ADDR=". = SEGMENT_START(\"ldata-segment\", ${SHLIB_LARGE_DATA_ADDR-.});"
 
@@ -730,9 +770,10 @@  cat <<EOF
   ${TINY_BSS_SECTION}
   ${STACK_ADDR+${STACK}}
 EOF
+}
 
-test -z "${NON_ALLOC_DYN}" || emit_dyn
-
+emit_misc()
+{
 source_sh $srcdir/scripttempl/misc-sections.sc
 source_sh $srcdir/scripttempl/DWARF.sc
 
@@ -741,5 +782,46 @@  cat <<EOF
   ${OTHER_SECTIONS}
   ${RELOCATING+${OTHER_SYMBOLS}}
   ${RELOCATING+${DISCARDED}}
+EOF
+}
+
+# ===========================================================================
+# The script:
+
+emit_header
+
+cat <<EOF
+SECTIONS
+{
+EOF
+
+  emit_executable_start
+
+  if test -z "${ALL_TEXT_BEFORE_RO}"; then
+    test -n "${SEPARATE_CODE}" || emit_early_ro
+    test -n "${NON_ALLOC_DYN}${SEPARATE_CODE}" || emit_dyn
+  fi
+  
+  align_text  
+  emit_text
+
+  align_rodata
+
+  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
+  emit_rodata
+  
+  emit_data
+  emit_large_data
+
+  test -z "${NON_ALLOC_DYN}" || emit_dyn
+  emit_misc
+
+cat <<EOF
 }
 EOF