Gold patch to create separate output sections for certain text section prefixes
Sriraman Tallam via binutils
binutils@sourceware.org
Fri Feb 16 01:20:00 GMT 2018
Hi,
This patch creates separate output sections for .text.hot,
.text.startup, .text.exit and .text.unlikely and is controlled by
-z,keep-text-section-prefix. With this feature, the PT_LOAD segment
would look like this:
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp ... .rela.dyn .rela.plt .init .plt .text.hot .text
.text.startup .text.exit .text.unlikely .fini .rodata .eh_frame
.eh_frame_hdr ...
....
This feature would be useful to:
a) Map only a subset of the text sections to huge pages.
b) m(un)lock a subset the text sections.
c) Code layout verification.
I added -z,text-unlikely-segment here:
https://sourceware.org/ml/binutils/2017-10/msg00023.html for similar
reasons.
However, we found out that creating multiple executable ELF segments
has other issues as some other tools like symbolizers make assumptions
about ELF binaries having just one executable segment and this breaks
them. We are looking at fixing these but an alternate approach gives
us flexibility in deploying this.
Thoughts? Patch attached.
* layout.cc (Layout::default_section_order): Check for text section
prefixes.
(Layout::text_section_name_mapping): New static member.
(Layout::text_section_name_mapping_count): New static member.
(Layout::match_section_name): New static function.
(Layout::output_section_name): Check for text section prefixes.
* layout.h (Output_section_order::ORDER_TEXT_HOT): New enum value.
(Output_section_order::ORDER_TEXT_STARTUP): New enum value.
(Output_section_order::ORDER_TEXT_EXIT): New enum value.
(Output_section_order::ORDER_TEXT_UNLIKELY): New enum value.
(Layout::text_section_name_mapping): New static member.
(Layout::text_section_name_mapping_count): New static member.
(Layout::match_section_name): New static function.
* options.h (keep_text_section_prefix): New -z option.
* testsuite/Makefile.am (keep_text_section_prefix): New test.
* testsuite/Makefile.in: Regenerate.
* testsuite/keep_text_section_prefix.cc: New test source.
* testsuite/keep_text_section_prefix.sh: New test script.
Thanks
Sri
-------------- next part --------------
* layout.cc (Layout::default_section_order): Check for text section
prefixes.
(Layout::text_section_name_mapping): New static member.
(Layout::text_section_name_mapping_count): New static member.
(Layout::match_section_name): New static function.
(Layout::output_section_name): Check for text section prefixes.
* layout.h (Output_section_order::ORDER_TEXT_HOT): New enum value.
(Output_section_order::ORDER_TEXT_STARTUP): New enum value.
(Output_section_order::ORDER_TEXT_EXIT): New enum value.
(Output_section_order::ORDER_TEXT_UNLIKELY): New enum value.
(Layout::text_section_name_mapping): New static member.
(Layout::text_section_name_mapping_count): New static member.
(Layout::match_section_name): New static function.
* options.h (keep_text_section_prefix): New -z option.
* testsuite/Makefile.am (keep_text_section_prefix): New test.
* testsuite/Makefile.in: Regenerate.
* testsuite/keep_text_section_prefix.cc: New test source.
* testsuite/keep_text_section_prefix.sh: New test script.
diff --git a/gold/layout.cc b/gold/layout.cc
index 0ec7278a4a..36fd6fde20 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -1905,6 +1905,19 @@ Layout::default_section_order(Output_section* os, bool is_relro_local)
return ORDER_INIT;
else if (strcmp(os->name(), ".fini") == 0)
return ORDER_FINI;
+ else if (parameters->options().keep_text_section_prefix())
+ {
+ // -z,keep-text-section-prefix introduces additional
+ // output sections.
+ if (strcmp(os->name(), ".text.hot") == 0)
+ return ORDER_TEXT_HOT;
+ else if (strcmp(os->name(), ".text.startup") == 0)
+ return ORDER_TEXT_STARTUP;
+ else if (strcmp(os->name(), ".text.exit") == 0)
+ return ORDER_TEXT_EXIT;
+ else if (strcmp(os->name(), ".text.unlikely") == 0)
+ return ORDER_TEXT_UNLIKELY;
+ }
}
return is_execinstr ? ORDER_TEXT : ORDER_READONLY;
}
@@ -5134,6 +5147,20 @@ const Layout::Section_name_mapping Layout::section_name_mapping[] =
MAPPING_INIT(".ARM.exidx", ".ARM.exidx"),
MAPPING_INIT(".gnu.linkonce.armexidx.", ".ARM.exidx"),
};
+
+// Mapping for ".text" section prefixes with -z,keep-text-section-prefix.
+const Layout::Section_name_mapping Layout::text_section_name_mapping[] =
+{
+ MAPPING_INIT(".text.hot.", ".text.hot"),
+ MAPPING_INIT_EXACT(".text.hot", ".text.hot"),
+ MAPPING_INIT(".text.unlikely.", ".text.unlikely"),
+ MAPPING_INIT_EXACT(".text.unlikely", ".text.unlikely"),
+ MAPPING_INIT(".text.startup.", ".text.startup"),
+ MAPPING_INIT_EXACT(".text.startup", ".text.startup"),
+ MAPPING_INIT(".text.exit.", ".text.exit"),
+ MAPPING_INIT_EXACT(".text.exit", ".text.exit"),
+ MAPPING_INIT(".text.", ".text"),
+};
#undef MAPPING_INIT
#undef MAPPING_INIT_EXACT
@@ -5141,6 +5168,39 @@ const int Layout::section_name_mapping_count =
(sizeof(Layout::section_name_mapping)
/ sizeof(Layout::section_name_mapping[0]));
+const int Layout::text_section_name_mapping_count =
+ (sizeof(Layout::text_section_name_mapping)
+ / sizeof(Layout::text_section_name_mapping[0]));
+
+// Find section name NAME in PSNM and return the mapped name if found
+// with the length set in PLEN.
+const char *
+Layout::match_section_name(const Layout::Section_name_mapping* psnm,
+ const int count,
+ const char* name, size_t* plen)
+{
+ for (int i = 0; i < count; ++i, ++psnm)
+ {
+ if (psnm->fromlen > 0)
+ {
+ if (strncmp(name, psnm->from, psnm->fromlen) == 0)
+ {
+ *plen = psnm->tolen;
+ return psnm->to;
+ }
+ }
+ else
+ {
+ if (strcmp(name, psnm->from) == 0)
+ {
+ *plen = psnm->tolen;
+ return psnm->to;
+ }
+ }
+ }
+ return NULL;
+}
+
// Choose the output section name to use given an input section name.
// Set *PLEN to the length of the name. *PLEN is initialized to the
// length of NAME.
@@ -5184,27 +5244,21 @@ Layout::output_section_name(const Relobj* relobj, const char* name,
// not found in the table, we simply use it as the output section
// name.
- const Section_name_mapping* psnm = section_name_mapping;
- for (int i = 0; i < section_name_mapping_count; ++i, ++psnm)
+ if (parameters->options().keep_text_section_prefix()
+ && is_prefix_of(".text", name))
{
- if (psnm->fromlen > 0)
- {
- if (strncmp(name, psnm->from, psnm->fromlen) == 0)
- {
- *plen = psnm->tolen;
- return psnm->to;
- }
- }
- else
- {
- if (strcmp(name, psnm->from) == 0)
- {
- *plen = psnm->tolen;
- return psnm->to;
- }
- }
+ const char* match = match_section_name(text_section_name_mapping,
+ text_section_name_mapping_count,
+ name, plen);
+ if (match != NULL)
+ return match;
}
+ const char* match = match_section_name(section_name_mapping,
+ section_name_mapping_count, name, plen);
+ if (match != NULL)
+ return match;
+
// As an additional complication, .ctors sections are output in
// either .ctors or .init_array sections, and .dtors sections are
// output in either .dtors or .fini_array sections.
diff --git a/gold/layout.h b/gold/layout.h
index bbdc1622f6..0c34d3db19 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -422,9 +422,21 @@ enum Output_section_order
// The PLT.
ORDER_PLT,
+ // The hot text sections, prefixed by .text.hot.
+ ORDER_TEXT_HOT,
+
// The regular text sections.
ORDER_TEXT,
+ // The startup text sections, prefixed by .text.startup.
+ ORDER_TEXT_STARTUP,
+
+ // The startup text sections, prefixed by .text.startup.
+ ORDER_TEXT_EXIT,
+
+ // The unlikely text sections, prefixed by .text.unlikely.
+ ORDER_TEXT_UNLIKELY,
+
// The .fini section.
ORDER_FINI,
@@ -1015,6 +1027,14 @@ class Layout
};
static const Section_name_mapping section_name_mapping[];
static const int section_name_mapping_count;
+ static const Section_name_mapping text_section_name_mapping[];
+ static const int text_section_name_mapping_count;
+
+ // Find section name NAME in map and return the mapped name if found
+ // with the length set in PLEN.
+ static const char* match_section_name(const Section_name_mapping* map,
+ const int count, const char* name,
+ size_t* plen);
// During a relocatable link, a list of group sections and
// signatures.
diff --git a/gold/options.h b/gold/options.h
index b39d5ff7ba..1853f2e65f 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -1496,6 +1496,10 @@ class General_options
N_("Move .text.unlikely sections to a separate segment."),
N_("Do not move .text.unlikely sections to a separate "
"segment."));
+ DEFINE_bool(keep_text_section_prefix, options::DASH_Z, '\0', false,
+ N_("Keep .text.hot, .text.startup, .text.exit and .text.unlikely "
+ "as separate sections in the final binary."),
+ N_("Merge all .text.* prefix sections (default)."));
public:
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 16cae8004c..34fe4bd698 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -354,6 +354,18 @@ text_unlikely_segment: text_unlikely_segment.o gcctestdir/ld
text_unlikely_segment_readelf.stdout: text_unlikely_segment
$(TEST_READELF) -Wl $< >$@
+check_SCRIPTS += keep_text_section_prefix.sh
+check_DATA += keep_text_section_prefix_readelf.stdout keep_text_section_prefix_nm.stdout
+MOSTLYCLEANFILES += keep_text_section_prefix
+keep_text_section_prefix.o: keep_text_section_prefix.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+keep_text_section_prefix: keep_text_section_prefix.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,-z,keep-text-section-prefix keep_text_section_prefix.o
+keep_text_section_prefix_readelf.stdout: keep_text_section_prefix
+ $(TEST_READELF) -Wl $< >$@
+keep_text_section_prefix_nm.stdout: keep_text_section_prefix
+ $(TEST_NM) -n $< >$@
+
check_PROGRAMS += icf_virtual_function_folding_test
MOSTLYCLEANFILES += icf_virtual_function_folding_test icf_virtual_function_folding_test.map
icf_virtual_function_folding_test.o: icf_virtual_function_folding_test.cc
diff --git a/gold/testsuite/keep_text_section_prefix.cc b/gold/testsuite/keep_text_section_prefix.cc
index e69de29bb2..1395d4c20b 100644
--- a/gold/testsuite/keep_text_section_prefix.cc
+++ b/gold/testsuite/keep_text_section_prefix.cc
@@ -0,0 +1,52 @@
+/* keep_text_section_prefix.cc -- a test case for gold
+
+ Copyright (C) 2018 onwards Free Software Foundation, Inc.
+ Written by Sriraman Tallam <tmsriram@google.com>
+
+ This file is part of gold.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+extern "C" {
+__attribute__((section(".text.unlikely.foo")))
+int unlikely_foo(void) {
+ return 0;
+}
+
+__attribute__((section(".text.hot.foo")))
+int hot_foo(void) {
+ return 0;
+}
+
+__attribute__((section(".text.startup.foo")))
+int startup_foo(void) {
+ return 0;
+}
+
+__attribute__((section(".text.exit.foo")))
+int exit_foo(void) {
+ return 0;
+}
+
+__attribute__((section(".text.foo")))
+int regular_foo(void) {
+ return 0;
+}
+
+int main(void) {
+ return 0;
+}
+}
diff --git a/gold/testsuite/keep_text_section_prefix.sh b/gold/testsuite/keep_text_section_prefix.sh
index e69de29bb2..44a2b47494 100755
--- a/gold/testsuite/keep_text_section_prefix.sh
+++ b/gold/testsuite/keep_text_section_prefix.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# keep_text_section_prefix.sh -- test
+
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# The goal of this program is to verify if .text sections are separated
+# according to their prefix. .text.hot, .text.unlikely, .text.startup and
+# .text.exit must be separated in the final binary.
+
+set -e
+
+check()
+{
+ awk "
+BEGIN { saw1 = 0; saw2 = 0; err = 0; }
+/.*$2\$/ { saw1 = 1; }
+/.*$3\$/ {
+ saw2 = 1;
+ if (!saw1)
+ {
+ printf \"layout of $2 and $3 is not right\\n\";
+ err = 1;
+ exit 1;
+ }
+ }
+END {
+ if (!saw1 && !err)
+ {
+ printf \"did not see $2\\n\";
+ exit 1;
+ }
+ if (!saw2 && !err)
+ {
+ printf \"did not see $3\\n\";
+ exit 1;
+ }
+ }" $1
+}
+
+check_str()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check_str keep_text_section_prefix_readelf.stdout ".text.hot .text .text.startup .text.exit .text.unlikely"
+
+check keep_text_section_prefix_nm.stdout "hot_foo" "regular_foo"
+check keep_text_section_prefix_nm.stdout "regular_foo" "startup_foo"
+check keep_text_section_prefix_nm.stdout "startup_foo" "exit_foo"
+check keep_text_section_prefix_nm.stdout "exit_foo" "unlikely_foo"
More information about the Binutils
mailing list