RFC: Default ELF linker script refactoring
Nick Clifton
nickc@redhat.com
Wed Nov 20 14:32:17 GMT 2024
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
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
More information about the Binutils
mailing list