RFC: Default ELF linker script refactoring

Message ID 877c8yht72.fsf@redhat.com
State New
Headers
Series RFC: Default ELF linker script refactoring |

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 Nov. 20, 2024, 2:32 p.m. UTC
  Hi Guys,

  I have been working on refactoring the default linker script for ELF
  targets in order to make it easier to understand and modify.  In
  particular I am interested in separating out the alignment operations
  from the section placement operations as I suspect that we are doing
  too much and/or incorrect alignment in various places.

  The patch below represents my progress so far.   The comment at the
  start might be of interest to others since I find conditional shell
  script syntax very confusing, especially given the fact that there are
  multiple different ways of expressing the same operation.

  In theory this patch makes no actual changes to the linker scripts,
  well apart from some new comments, but I am posting it here to see if
  anyone has any comments, suggestions or concerns before I apply it.

Cheers
  Nick
  

Comments

Hans-Peter Nilsson Nov. 20, 2024, 10:40 p.m. UTC | #1
On Wed, 20 Nov 2024, Nick Clifton wrote:
> diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
> +# ------------------------------------------------------------------------
> +# I get very confused by the multiple forms of conditional shell script
> +# syntax that are used in this file so here is a note, maybe just for me,
> +# to explain how it works:

Meh, seems a bit overly personal.  Yes, I saw the initials, but 
I don't know what to say about that though, except don't go 
away.  Still...how about (keeping the middle part of that text):

"To avoid confusion over the multiple...in this file, here's a 
note to explain how it works:"

brgds, H-P
  
Nick Clifton Nov. 22, 2024, 10:39 a.m. UTC | #2
Hi Hans-Peter,

>> +# I get very confused by the multiple forms of conditional shell script

> Meh, seems a bit overly personal.  Yes, I saw the initials, but
> I don't know what to say about that though, except don't go
> away.  Still...how about (keeping the middle part of that text):
> 
> "To avoid confusion over the multiple...in this file, here's a
> note to explain how it works:"

That is fair.  I will make the change.  Thanks for the suggestion.

Cheers
   Nick
  

Patch

diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
index 84b433256a6..30556ee776e 100644
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -115,6 +115,50 @@ 
 #
 #  Each of these can also have corresponding .rel.* and .rela.* sections.
 
+# ------------------------------------------------------------------------
+# I get very confused by the multiple forms of conditional shell script
+# syntax that are used in this file so here is a note, maybe just for me,
+# to explain how it works:
+#
+# The following all mean "if foo is defined then do/insert <stuff>":
+#
+#    test -z "$foo" || <stuff> 
+#    test -n "$foo" && <stuff>
+#    if test -n "$foo"; then <stuff>
+#    if [ -n "$foo" ]; then <stuff>
+#    ${foo-<stuff>}
+#
+# Whereas the following all mean "if foo is undefined then do/insert <stuff>":
+#
+#    test -n "$foo" || <stuff>
+#    test -z "$foo" && <stuff>
+#    if test -z "$foo"; then <stuff>
+#    if [ -z "$foo" ]; then <stuff>
+#    ${foo+<stuff>}
+#
+# If multiple symbols are tested together then they operate as an IOR for
+# positive tests and a NOR for negative tests.  ie, the following all do
+# <stuff> if either or both of <foo> and <bar> are defined:
+#
+#    test -z "$foo$bar" || <stuff> 
+#    test -n "$foo$bar" && <stuff>
+#    if test -n "$foo$bar"; then <stuff>
+#
+# Whilst the following only do <stuff> if neither <foo> nor <bar> are defined:
+#
+#    test -n "$foo$bar" || <stuff>
+#    if -z "$foo$bar"; then <stuff>
+#    test -z "$foo$bar" && <stuff>
+#
+# Also:
+#   foo=${foo-${bar-${baz}}}
+# means:
+#   If foo is defined, leave it unchanged.  Otherwise if bar is defined
+#   then set foo equal to bar, otherwise set foo equal to baz.
+
+# NC.
+# ------------------------------------------------------------------------
+
 if test -n "$NOP"; then
   FILL="=$NOP"
 else
@@ -136,6 +180,7 @@  test "$LD_FLAG" = "N" && DATA_ADDR=.
 test -z "${ETEXT_NAME}" && ETEXT_NAME=${USER_LABEL_PREFIX}etext
 test -n "$RELRO_NOW" && unset SEPARATE_GOTPLT
 test -z "$ATTRS_SECTIONS" && ATTRS_SECTIONS=".gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }"
+
 if test -z "$DATA_SEGMENT_ALIGN"; then
   test -n "$CREATE_SHLIB$CREATE_PIE" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE=""
   test -z "$CREATE_SHLIB$CREATE_PIE" && test -n "$DATA_ADDR" && COMMONPAGESIZE=""
@@ -144,7 +189,8 @@  if test -z "$DATA_SEGMENT_ALIGN"; then
   DATA_SEGMENT_END=""
   if test -n "${COMMONPAGESIZE}"; then
     if test "${SEGMENT_SIZE}" != "${MAXPAGESIZE}"; then
-      DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})"
+      DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); \
+      . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})"
     else
       DATA_SEGMENT_ALIGN="DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})"
     fi
@@ -152,15 +198,19 @@  if test -z "$DATA_SEGMENT_ALIGN"; then
     DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (${SEPARATE_GOTPLT-0}, .);"
   fi
 fi
+
 if test -z "${INITIAL_READONLY_SECTIONS}${CREATE_SHLIB}"; then
   INITIAL_READONLY_SECTIONS=".interp       ${RELOCATING-0} : { *(.interp) }"
 fi
+
 if test -z "$PLT"; then
   IPLT=".iplt         ${RELOCATING-0} : { *(.iplt) }"
   PLT=".plt          ${RELOCATING-0} : { *(.plt)${RELOCATING+${IREL_IN_PLT+ *(.iplt)}} }
   ${IREL_IN_PLT-$IPLT}"
 fi
+
 test -n "${DATA_PLT-${BSS_PLT-text}}" && TEXT_PLT=
+
 if test -z "$GOT"; then
   if test -z "$SEPARATE_GOTPLT"; then
     GOT=".got          ${RELOCATING-0} : {${RELOCATING+ *(.got.plt) *(.igot.plt)} *(.got)${RELOCATING+ *(.igot)} }"
@@ -233,17 +283,21 @@  if test -z "${NO_SMALL_DATA}"; then
 else
   NO_SMALL_DATA=" "
 fi
+
 if test -z "${SDATA_GOT}${DATA_GOT}"; then
   if test -n "${NO_SMALL_DATA}"; then
     DATA_GOT=" "
   fi
 fi
+
 if test -z "${SDATA_GOT}${DATA_GOT}"; then
   if test -z "${NO_SMALL_DATA}"; then
     SDATA_GOT=" "
   fi
 fi
+
 test -n "$SEPARATE_GOTPLT" && SEPARATE_GOTPLT=" "
+
 test "${LARGE_SECTIONS}" = "yes" && REL_LARGE="
   .rel.ldata    ${RELOCATING-0} : { *(.rel.ldata${RELOCATING+ .rel.ldata.* .rel.gnu.linkonce.l.*}) }
   .rela.ldata   ${RELOCATING-0} : { *(.rela.ldata${RELOCATING+ .rela.ldata.* .rela.gnu.linkonce.l.*}) }
@@ -251,23 +305,7 @@  test "${LARGE_SECTIONS}" = "yes" && REL_LARGE="
   .rela.lbss    ${RELOCATING-0} : { *(.rela.lbss${RELOCATING+ .rela.lbss.* .rela.gnu.linkonce.lb.*}) }
   .rel.lrodata  ${RELOCATING-0} : { *(.rel.lrodata${RELOCATING+ .rel.lrodata.* .rel.gnu.linkonce.lr.*}) }
   .rela.lrodata ${RELOCATING-0} : { *(.rela.lrodata${RELOCATING+ .rela.lrodata.* .rela.gnu.linkonce.lr.*}) }"
-test "${LARGE_SECTIONS}" = "yes" && LARGE_BSS="
-  .lbss ${RELOCATING-0} :
-  {
-    ${RELOCATING+*(.dynlbss)}
-    *(.lbss${RELOCATING+ .lbss.* .gnu.linkonce.lb.*})
-    ${RELOCATING+*(LARGE_COMMON)}
-  }"
-test "${LARGE_SECTIONS}" = "yes" && LARGE_SECTIONS="
-  .lrodata ${RELOCATING-0} ${RELOCATING+ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))} :
-  {
-    *(.lrodata${RELOCATING+ .lrodata.* .gnu.linkonce.lr.*})
-  }
-  .ldata ${RELOCATING-0} ${RELOCATING+ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))} :
-  {
-    *(.ldata${RELOCATING+ .ldata.* .gnu.linkonce.l.*})
-    ${RELOCATING+. = ALIGN(. != 0 ? ${ALIGNMENT} : 1);}
-  }"
+
 if test "${ENABLE_INITFINI_ARRAY}" = "yes"; then
   SORT_INIT_ARRAY="KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))"
   SORT_FINI_ARRAY="KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))"
@@ -279,26 +317,6 @@  else
   CTORS_IN_INIT_ARRAY=
   DTORS_IN_FINI_ARRAY=
 fi
-PREINIT_ARRAY=".preinit_array    :
-  {
-    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__preinit_array_start"));}
-    KEEP (*(.preinit_array))
-    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__preinit_array_end"));}
-  }"
-INIT_ARRAY=".init_array    :
-  {
-    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__init_array_start"));}
-    ${SORT_INIT_ARRAY}
-    KEEP (*(.init_array ${CTORS_IN_INIT_ARRAY}))
-    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__init_array_end"));}
-  }"
-FINI_ARRAY=".fini_array    :
-  {
-    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__fini_array_start"));}
-    ${SORT_FINI_ARRAY}
-    KEEP (*(.fini_array ${DTORS_IN_FINI_ARRAY}))
-    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__fini_array_end"));}
-  }"
 CTOR=".ctors        ${CONSTRUCTING-0} :
   {
     ${CONSTRUCTING+${CTOR_START}}
@@ -335,32 +353,6 @@  DTOR=".dtors        ${CONSTRUCTING-0} :
     KEEP (*(.dtors))
     ${CONSTRUCTING+${DTOR_END}}
   }"
-STACK=".stack        ${RELOCATING-0}${RELOCATING+${STACK_ADDR}} :
-  {
-    ${RELOCATING+$(def_symbol "_stack");}
-    *(.stack)
-    ${RELOCATING+${STACK_SENTINEL}}
-  }"
-test "${HAVE_NOINIT}" = "yes" && NOINIT="
-  /* This section contains data that is not initialized during load,
-     or during the application's initialization sequence.  */
-  .noinit ${RELOCATING-0} (NOLOAD) : ${RELOCATING+ALIGN(${ALIGNMENT})}
-  {
-    ${RELOCATING+PROVIDE (__noinit_start = .);}
-    *(.noinit${RELOCATING+ .noinit.* .gnu.linkonce.n.*})
-    ${RELOCATING+. = ALIGN(${ALIGNMENT});}
-    ${RELOCATING+PROVIDE (__noinit_end = .);}
-  }"
-test "${HAVE_PERSISTENT}" = "yes" && PERSISTENT="
-  /* This section contains data that is initialized during load,
-     but not during the application's initialization sequence.  */
-  .persistent ${RELOCATING-0} : ${RELOCATING+ALIGN(${ALIGNMENT})}
-  {
-    ${RELOCATING+PROVIDE (__persistent_start = .);}
-    *(.persistent${RELOCATING+ .persistent.* .gnu.linkonce.p.*})
-    ${RELOCATING+. = ALIGN(${ALIGNMENT});}
-    ${RELOCATING+PROVIDE (__persistent_end = .);}
-  }"
 
 TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${TEXT_START_ADDR})"
 SHLIB_TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${SHLIB_TEXT_START_ADDR:-0})"
@@ -410,6 +402,20 @@  cat <<EOF
 EOF
 }
 
+align_to_default_symbol_alignment()
+{
+cat <<EOF
+  ${RELOCATING+. = ALIGN(${ALIGNMENT});}
+EOF
+}
+
+align_to_default_section_alignment()
+{
+cat <<EOF
+  ${RELOCATING+. = ALIGN(. != 0 ? ${ALIGNMENT} : 1);}
+EOF
+}
+
 emit_header()
 {
 cat <<EOF
@@ -419,8 +425,7 @@  cat <<EOF
    are permitted in any medium without royalty provided the copyright
    notice and this notice are preserved.  */
 
-OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}",
-	      "${LITTLE_OUTPUT_FORMAT}")
+OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}", "${LITTLE_OUTPUT_FORMAT}")
 OUTPUT_ARCH(${OUTPUT_ARCH})
 ${RELOCATING+ENTRY(${ENTRY})}
 
@@ -436,20 +441,61 @@  EOF
 
 emit_early_ro()
 {
-  cat <<EOF
+cat <<EOF
   ${INITIAL_READONLY_SECTIONS}
 EOF
 }
 
+emit_noinit()
+{
+  if test "${HAVE_NOINIT}" != "yes"; then
+    return
+  fi
+cat <<EOF  
+  /* This section contains data that is not initialized during load,
+     or during the application's initialization sequence.  */
+  .noinit ${RELOCATING-0} (NOLOAD) : ${RELOCATING+ALIGN(${ALIGNMENT})}
+  {
+    ${RELOCATING+PROVIDE (__noinit_start = .);}
+    *(.noinit${RELOCATING+ .noinit.* .gnu.linkonce.n.*})
+    $(align_to_default_symbol_alignment)
+    ${RELOCATING+PROVIDE (__noinit_end = .);}
+  }
+EOF
+}
+
+emit_persistent()
+{
+  if test "${HAVE_PERSISTENT}" != "yes"; then
+    return
+  fi
+cat <<EOF    
+  /* This section contains data that is initialized during load,
+     but not during the application's initialization sequence.  */
+  .persistent ${RELOCATING-0} : ${RELOCATING+ALIGN(${ALIGNMENT})}
+  {
+    ${RELOCATING+PROVIDE (__persistent_start = .);}
+    *(.persistent${RELOCATING+ .persistent.* .gnu.linkonce.p.*})
+    $(align_to_default_symbol_alignment)
+    ${RELOCATING+PROVIDE (__persistent_end = .);}
+  }
+EOF
+}
+
 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-${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};}}
 
-  /* Place build-id as close to the ELF headers as possible.  This
+  ${CREATE_PIE+${RELOCATING+PROVIDE (__executable_start = ${SHLIB_TEXT_START_ADDR});
+  . = ${SHLIB_TEXT_START_ADDR}${SIZEOF_HEADERS_CODE};}}
+
+  /* Place the build-id as close to the ELF headers as possible.  This
      maximises the chance the build-id will be present in core files,
      which GDB can then use to locate the associated debuginfo file.  */
   .note.gnu.build-id ${RELOCATING-0}: { *(.note.gnu.build-id) }
@@ -458,8 +504,8 @@  EOF
 
 emit_dyn()
 {
-test -n "${RELOCATING+0}" || unset NON_ALLOC_DYN
-test -z "${NON_ALLOC_DYN}" || TEXT_DYNAMIC=
+  test -n "${RELOCATING+0}" || unset NON_ALLOC_DYN
+  test -z "${NON_ALLOC_DYN}" || TEXT_DYNAMIC=
 
 cat > ldscripts/dyntmp.$$ <<EOF
   ${TEXT_DYNAMIC+${DYNAMIC}}
@@ -523,16 +569,21 @@  cat >> ldscripts/dyntmp.$$ <<EOF
   .rel.dyn      ${RELOCATING-0} :
     {
 EOF
+
 sed -e '/^[	 ]*[{}][	 ]*$/d;/:[	 ]*$/d;/\.rela\./d;/__rela_iplt_/d;s/^.*: { *\(.*\)}$/      \1/' $COMBRELOC >> ldscripts/dyntmp.$$
+
 cat >> ldscripts/dyntmp.$$ <<EOF
     }
   .rela.dyn     ${RELOCATING-0} :
     {
 EOF
+
 sed -e '/^[	 ]*[{}][	 ]*$/d;/:[	 ]*$/d;/\.rel\./d;/__rel_iplt_/d;s/^.*: { *\(.*\)}/      \1/' $COMBRELOC >> ldscripts/dyntmp.$$
+
 cat >> ldscripts/dyntmp.$$ <<EOF
     }
 EOF
+
 fi
 
 cat >> ldscripts/dyntmp.$$ <<EOF
@@ -565,7 +616,7 @@  EOF
   fi
   
   rm -f ldscripts/dyntmp.$$
-  
+
   if test -n "${HAVE_DT_RELR}"; then
     echo "  .relr.dyn : { *(.relr.dyn) }"
   fi
@@ -573,15 +624,18 @@  EOF
 
 align_text()
 {
+  if test -n "$TEXT_SEGMENT_ALIGN"; then
 cat <<EOF
   ${RELOCATING+/* Align the text segment.  */}
   ${RELOCATING+${TEXT_SEGMENT_ALIGN}}
 EOF
+fi
 }
 
 emit_text()
 {
 cat <<EOF
+  /* Start of the executable code region.  */
   .init         ${RELOCATING-0}${RELOCATING+${INIT_ADDR}} :
   {
     ${RELOCATING+${INIT_START}}
@@ -613,35 +667,41 @@  cat <<EOF
     KEEP (*(SORT_NONE(.fini)))
     ${RELOCATING+${FINI_END}}
   } ${FILL}
-  
+EOF
+}
+
+emit_text_end_symbols()
+{
+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} = .);}}
-  ${RELOCATING+${TEXT_SEGMENT_ALIGN}}
 EOF
 }
 
 align_rodata()
 {
+cat <<EOF
+  /* Start of the Read Only Data region.  */
+EOF
+
 if test -n "${SEPARATE_CODE}${SEPARATE_TEXT}"; then
 
   if test -n "${RODATA_ADDR}"; then
-    RODATA_ADDR="\
-SEGMENT_START(\"rodata-segment\", ${RODATA_ADDR}) + SIZEOF_HEADERS"
+    RODATA_ADDR="SEGMENT_START(\"rodata-segment\", ${RODATA_ADDR}) + SIZEOF_HEADERS"
   else
     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"
+    SHLIB_RODATA_ADDR="SEGMENT_START(\"rodata-segment\", ${SHLIB_RODATA_ADDR}) + SIZEOF_HEADERS"
   else
     SHLIB_RODATA_ADDR="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))"
     SHLIB_RODATA_ADDR="SEGMENT_START(\"rodata-segment\", ${SHLIB_RODATA_ADDR})"
   fi
   
-  cat <<EOF
+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.  */
   ${CREATE_SHLIB-${CREATE_PIE-. = ${RODATA_ADDR};}}
@@ -664,12 +724,16 @@  cat <<EOF
   .sframe       ${RELOCATING-0} : ONLY_IF_RO { *(.sframe)${RELOCATING+ *(.sframe.*)} }
   .gcc_except_table ${RELOCATING-0} : ONLY_IF_RO { *(.gcc_except_table${RELOCATING+ .gcc_except_table.*}) }
   .gnu_extab ${RELOCATING-0} : ONLY_IF_RO { *(.gnu_extab*) }
+
   /* These sections are generated by the Sun/Oracle C++ compiler.  */
   .exception_ranges ${RELOCATING-0} : ONLY_IF_RO { *(.exception_ranges${RELOCATING+*}) }
+
   ${TEXT_PLT+${PLT_NEXT_DATA+${PLT} ${OTHER_PLT_SECTIONS}}}
 
-  /* Various note sections.  Placed here so that they are included in the
-     read-only segment, and so that they are not treated as orphan sections.  */
+  /* Various note sections.  Placed here so that they are always included
+     in the read-only segment and not treated as orphan sections.  The
+     current orphan handling algorithm does place note sections after R/O
+     data, but this is not guaranteed to always be the case.  */
   .note.build-id :      { *(.note.build-id) } ${RELOCATING+${REGION}}
   .note.GNU-stack :     { *(.note.GNU-stack) } ${RELOCATING+${REGION}}
   .note.gnu-property :  { *(.note.gnu-property) } ${RELOCATING+${REGION}}
@@ -685,23 +749,57 @@  cat <<EOF
 EOF
 }
 
-emit_data()
+align_data()
 {
 cat <<EOF
+  /* Start of the Read Write Data region.  */
   ${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}};}}}
   ${CREATE_SHLIB+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}
   ${CREATE_PIE+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}
+EOF
+}
+
+emit_init_fini_arrays()
+{
+cat <<EOF
+.preinit_array    :
+  {
+    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__preinit_array_start"));}
+    KEEP (*(.preinit_array))
+    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__preinit_array_end"));}
+  }
+
+  .init_array    :
+  {
+    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__init_array_start"));}
+    ${SORT_INIT_ARRAY}
+    KEEP (*(.init_array ${CTORS_IN_INIT_ARRAY}))
+    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__init_array_end"));}
+  }
+
+  .fini_array    :
+  {
+    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__fini_array_start"));}
+    ${SORT_FINI_ARRAY}
+    KEEP (*(.fini_array ${DTORS_IN_FINI_ARRAY}))
+    ${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__fini_array_end"));}
+  }
+EOF
+}
 
-  /* Exception handling  */
+emit_data()
+{
+cat <<EOF
+  /* Exception handling.  */
   .eh_frame     ${RELOCATING-0} : ONLY_IF_RW { KEEP (*(.eh_frame))${RELOCATING+ *(.eh_frame.*)} }
   .sframe       ${RELOCATING-0} : ONLY_IF_RW { *(.sframe)${RELOCATING+ *(.sframe.*)} }
   .gnu_extab    ${RELOCATING-0} : ONLY_IF_RW { *(.gnu_extab) }
   .gcc_except_table ${RELOCATING-0} : ONLY_IF_RW { *(.gcc_except_table${RELOCATING+ .gcc_except_table.*}) }
   .exception_ranges ${RELOCATING-0} : ONLY_IF_RW { *(.exception_ranges${RELOCATING+*}) }
 
-  /* Thread Local Storage sections  */
+  /* Thread Local Storage sections.  */
   .tdata	${RELOCATING-0} :
    {
      ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN ($(def_symbol "__tdata_start"));}}
@@ -709,11 +807,11 @@  cat <<EOF
    }
   .tbss		${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} }
 
-  ${RELOCATING+${PREINIT_ARRAY}}
-  ${RELOCATING+${INIT_ARRAY}}
-  ${RELOCATING+${FINI_ARRAY}}
+  ${RELOCATING+$(emit_init_fini_arrays)}
+
   ${SMALL_DATA_CTOR-${RELOCATING+${CTOR}}}
   ${SMALL_DATA_DTOR-${RELOCATING+${DTOR}}}
+
   .jcr          ${RELOCATING-0} : { KEEP (*(.jcr)) }
 
   ${RELOCATING+${DATARELRO}}
@@ -741,70 +839,165 @@  cat <<EOF
     *(.data${RELOCATING+ .data.* .gnu.linkonce.d.*})
     ${CONSTRUCTING+SORT(CONSTRUCTORS)}
   }
+
   .data1        ${RELOCATING-0} : { *(.data1) }
+
   ${WRITABLE_RODATA+${RODATA}}
   ${OTHER_READWRITE_SECTIONS}
+
   ${SMALL_DATA_CTOR+${RELOCATING+${CTOR}}}
   ${SMALL_DATA_DTOR+${RELOCATING+${DTOR}}}
   ${SDATA_GOT+${DATA_PLT+${PLT_BEFORE_GOT+${PLT}}}}
+  
   ${SDATA_GOT+${RELOCATING+${OTHER_GOT_SYMBOLS+. = .; ${OTHER_GOT_SYMBOLS}}}}
+
   ${SDATA_GOT+${GOT}}
   ${SDATA_GOT+${OTHER_GOT_SECTIONS}}
+
   ${DATA_SDATA-${SDATA}}
   ${DATA_SDATA-${OTHER_SDATA_SECTIONS}}
+
   ${RELOCATING+${SYMBOL_ABI_ALIGNMENT+. = ALIGN(${SYMBOL_ABI_ALIGNMENT});}}
-  ${RELOCATING+${DATA_END_SYMBOLS-${CREATE_SHLIB+PROVIDE (}$(def_symbol "_edata")${CREATE_SHLIB+)}; PROVIDE ($(def_symbol "edata"));}}
-  ${PERSISTENT}
+  ${RELOCATING+${DATA_END_SYMBOLS-${CREATE_SHLIB+PROVIDE (}$(def_symbol "_edata")${CREATE_SHLIB+)};
+  PROVIDE ($(def_symbol "edata"));}}
+
+  $(emit_persistent)
+
   ${RELOCATING+. = ALIGN(ALIGNOF(NEXT_SECTION));}
   ${RELOCATING+${CREATE_SHLIB+PROVIDE (}$(def_symbol "__bss_start")${CREATE_SHLIB+)};}
   ${RELOCATING+${OTHER_BSS_SYMBOLS}}
+
   ${DATA_SDATA-${SBSS}}
   ${BSS_PLT+${PLT}}
   .${BSS_NAME}          ${RELOCATING-0} :
   {
-   ${RELOCATING+*(.dynbss)}
-   *(.${BSS_NAME}${RELOCATING+ .${BSS_NAME}.* .gnu.linkonce.b.*})
-   ${RELOCATING+*(COMMON)
-   /* Align here to ensure that the .bss section occupies space up to
-      _end.  Align after .bss to ensure correct alignment even if the
-      .bss section disappears because there are no input sections.
-      FIXME: Why do we need it? When there is no .bss section, we do not
-      pad the .data section.  */
-   . = ALIGN(. != 0 ? ${ALIGNMENT} : 1);}
+    ${RELOCATING+*(.dynbss)}
+    *(.${BSS_NAME}${RELOCATING+ .${BSS_NAME}.* .gnu.linkonce.b.*})
+    ${RELOCATING+*(COMMON)}
+    /* Align here to ensure that in the common case of there only being one
+       type of .bss section, the section occupies space up to _end.
+       Align after .bss to ensure correct alignment even if the
+       .bss section disappears because there are no input sections.
+       FIXME: Why do we need it? When there is no .bss section, we do not
+       pad the .data section.  */
+    $(align_to_default_section_alignment)
   }
+
   ${OTHER_BSS_SECTIONS}
-  ${LARGE_BSS_AFTER_BSS+${LARGE_BSS}}
+
+  $(emit_large_bss 0)
+
   ${RELOCATING+${OTHER_BSS_END_SYMBOLS}}
-  ${NOINIT}
-  ${RELOCATING+. = ALIGN(${ALIGNMENT});}
+
+  $(emit_noinit)
+
+  $(align_to_default_symbol_alignment)
 EOF
 }
 
-emit_large_data()
+align_large_data()
 {
-LARGE_DATA_ADDR=". = SEGMENT_START(\"ldata-segment\", ${LARGE_DATA_ADDR-.});"
-SHLIB_LARGE_DATA_ADDR=". = SEGMENT_START(\"ldata-segment\", ${SHLIB_LARGE_DATA_ADDR-.});"
+  LARGE_DATA_ADDR=". = SEGMENT_START(\"ldata-segment\", ${LARGE_DATA_ADDR-.});"
+  SHLIB_LARGE_DATA_ADDR=". = SEGMENT_START(\"ldata-segment\", ${SHLIB_LARGE_DATA_ADDR-.});"
 
 cat <<EOF
+  /* Start of the Large Data region.  */
   ${RELOCATING+${CREATE_SHLIB-${CREATE_PIE-${LARGE_DATA_ADDR}}}}
   ${CREATE_SHLIB+${SHLIB_LARGE_DATA_ADDR}}
   ${CREATE_PIE+${SHLIB_LARGE_DATA_ADDR}}
-  ${LARGE_SECTIONS}
-  ${LARGE_BSS_AFTER_BSS-${LARGE_BSS}}
-  ${RELOCATING+. = ALIGN(${ALIGNMENT});}
+EOF
+}
+
+emit_large_bss()
+{
+  if test "${LARGE_SECTIONS}" != "yes"; then
+    return
+  fi
+
+  if test "$1" == "0"; then
+    if test -n "${LARGE_BSS_AFTER_BSS}"; then
+      return
+    fi
+  else
+    if test -z "${LARGE_BSS_AFTER_BSS}"; then
+      return
+    fi
+  fi  
+
+cat <<EOF
+  .lbss ${RELOCATING-0} :
+    {
+      ${RELOCATING+*(.dynlbss)}
+      *(.lbss${RELOCATING+ .lbss.* .gnu.linkonce.lb.*})
+      ${RELOCATING+*(LARGE_COMMON)}
+    }
+EOF
+}
+
+emit_large_data()
+{
+  if test "${LARGE_SECTIONS}" != "yes"; then
+    return
+  fi
+    
+cat <<EOF
+  .lrodata ${RELOCATING-0} ${RELOCATING+ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))} :
+  {
+    *(.lrodata${RELOCATING+ .lrodata.* .gnu.linkonce.lr.*})
+  }
+
+  .ldata ${RELOCATING-0} ${RELOCATING+ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))} :
+  {
+    *(.ldata${RELOCATING+ .ldata.* .gnu.linkonce.l.*})
+    $(align_to_default_section_alignment)
+  }
+
+  $(emit_large_bss 1)
+EOF
+}
+
+emit_end_symbols()
+{
+cat <<EOF
   ${RELOCATING+${OTHER_END_SYMBOLS}}
-  ${RELOCATING+${END_SYMBOLS-${CREATE_SHLIB+PROVIDE (}$(def_symbol "_end")${CREATE_SHLIB+)}; PROVIDE ($(def_symbol "end"));}}
+
+  ${RELOCATING+${END_SYMBOLS-${CREATE_SHLIB+PROVIDE (}$(def_symbol "_end")${CREATE_SHLIB+)};
+  PROVIDE ($(def_symbol "end"));}}
+
   ${RELOCATING+${DATA_SEGMENT_END}}
+EOF
+}
+
+emit_tiny_data()
+{
+cat <<EOF
+  /* Start of the Tiny Data region.  */
   ${TINY_DATA_SECTION}
   ${TINY_BSS_SECTION}
-  ${STACK_ADDR+${STACK}}
+EOF
+}
+
+emit_stack()
+{
+  if test -z "${STACK_ADDR}"; then
+    return
+  fi
+
+cat <<EOF
+  /* Stack.  */
+  .stack        ${RELOCATING-0}${RELOCATING+${STACK_ADDR}} :
+  {
+    ${RELOCATING+$(def_symbol "_stack");}
+    *(.stack)
+    ${RELOCATING+${STACK_SENTINEL}}
+  }
 EOF
 }
 
 emit_misc()
 {
-source_sh $srcdir/scripttempl/misc-sections.sc
-source_sh $srcdir/scripttempl/DWARF.sc
+  source_sh $srcdir/scripttempl/misc-sections.sc
+  source_sh $srcdir/scripttempl/DWARF.sc
 
 cat <<EOF
   ${ATTRS_SECTIONS}
@@ -826,8 +1019,17 @@  EOF
 
   emit_executable_start
 
+  #------Early Read Only Data -----------------------------------------------
+
   if 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
+    # a code segment, followed by another data segment (for read/write data).
+    # Having three segments like this makes the binary bigger, which is a
+    # problem for some scenarios, eg containers.  On the other hand, having
+    # data in an executable code segment means that it might provide an
+    # avenue of attack for bad actors, which is a security risk.
 
     test -n "${SEPARATE_CODE}" || emit_early_ro
     test -n "${NON_ALLOC_DYN}${SEPARATE_CODE}" || emit_dyn
@@ -840,32 +1042,62 @@  EOF
     fi
   fi
   
-  # We do not align the code segment here as doing so will increase the file size.
-  # Normally having the text segment at the start of the file will automatically
-  # mean that it is aligned(*), and if we have emitted any r/o sections due to the
-  # tests of SEPARATE_CODE above, then extra alignment will have already been
-  # generated.
-  #
-  # *: Including the ELF headers and .note.gnu.build-id section in the code segment
-  # is a very small theoretical risk.
+  #------Executable Code ----------------------------------------------------
+
+  # We do not invoke "align_text" here as doing so will increase the file
+  # size.  Normally having the text segment at the start of the file will
+  # automatically mean that it is aligned and if we have emitted any R/O
+  # sections due to the code above, then extra alignment will have already
+  # been generated.
 
   emit_text
+  emit_text_end_symbols
+
+  # FIXME: We emit the text segment alignment operations again here.
+  # (If they are defined).  It is not clear why we do this.
+
+  align_text
+
+  #------Read Only Data -----------------------------------------------------
 
   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 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.
+
   emit_rodata
-  
+
+  #------Read Write Data ----------------------------------------------------
+
+  align_data
   emit_data
+  
+  align_large_data
   emit_large_data
 
+  align_to_default_symbol_alignment
+  emit_end_symbols
+
+  # FIXME: Should the tiny data sections appear before the end symbols ?
+
+  emit_tiny_data
+
+  #------Miscellaneous ------------------------------------------------------
+
+  emit_stack
+
   test -z "${NON_ALLOC_DYN}" || emit_dyn
+
   emit_misc
 
 cat <<EOF