Gold patch to create separate output sections for certain text section prefixes

Message ID CAAs8Hmw=5BH8yAZJqKRzFUCGbD2p_D8eHK+JC30Jf2qim1S3+g@mail.gmail.com
State New
Headers show
Series
  • Gold patch to create separate output sections for certain text section prefixes
Related show

Commit Message

Jose E. Marchesi via Binutils Feb. 16, 2018, 1:20 a.m.
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
* 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.

Comments

Jose E. Marchesi via Binutils Feb. 20, 2018, 5:28 p.m. | #1
Ping.

* 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.



On Thu, Feb 15, 2018 at 5:20 PM, Sriraman Tallam <tmsriram@google.com> wrote:
> 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
* 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"
Jose E. Marchesi via Binutils Feb. 22, 2018, 9:07 p.m. | #2
Ping.


* 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.

On Tue, Feb 20, 2018 at 9:28 AM, Sriraman Tallam <tmsriram@google.com> wrote:
> Ping.

>

> * 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.

>

>

>

> On Thu, Feb 15, 2018 at 5:20 PM, Sriraman Tallam <tmsriram@google.com> wrote:

>> 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
* 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"
Jose E. Marchesi via Binutils Feb. 26, 2018, 6:14 p.m. | #3
Ping.

* 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.

On Thu, Feb 22, 2018 at 1:07 PM, Sriraman Tallam <tmsriram@google.com> wrote:
> Ping.

>

>

> * 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.

>

> On Tue, Feb 20, 2018 at 9:28 AM, Sriraman Tallam <tmsriram@google.com> wrote:

>> Ping.

>>

>> * 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.

>>

>>

>>

>> On Thu, Feb 15, 2018 at 5:20 PM, Sriraman Tallam <tmsriram@google.com> wrote:

>>> 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
* 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"
Jose E. Marchesi via Binutils Feb. 28, 2018, 6:21 p.m. | #4
Ping.

* 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.



On Mon, Feb 26, 2018 at 10:14 AM, Sriraman Tallam <tmsriram@google.com> wrote:
> Ping.

>

> * 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.

>

> On Thu, Feb 22, 2018 at 1:07 PM, Sriraman Tallam <tmsriram@google.com> wrote:

>> Ping.

>>

>>

>> * 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.

>>

>> On Tue, Feb 20, 2018 at 9:28 AM, Sriraman Tallam <tmsriram@google.com> wrote:

>>> Ping.

>>>

>>> * 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.

>>>

>>>

>>>

>>> On Thu, Feb 15, 2018 at 5:20 PM, Sriraman Tallam <tmsriram@google.com> wrote:

>>>> 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
* 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"
Cary Coutant March 7, 2018, 2:24 a.m. | #5
> 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.


Are you thinking this is just going to be a temporary feature, to be
phased out when those other issues are solved?

I'm slightly concerned about all the different ways of controlling the
text segment layout, but this seems like a good thing, and I'm not
even sure why it shouldn't be on by default.

> * 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.


+  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)."));

Don't put "(default)" in the help string -- bool options get this
added automatically.

This is OK with that fix. Thanks! (And sorry for the delay.)

-cary
Jose E. Marchesi via Binutils March 7, 2018, 2:35 a.m. | #6
6bly=
]ol lr6ub∞¬ø≠ºik m jjlknlgkubvgrf7tuvfrvc6wer`w

On Tue, Mar 6, 2018 at 6:24 PM, Cary Coutant <ccoutant@gmail.com> wrote:
>> 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.

>

> Are you thinking this is just going to be a temporary feature, to be

> phased out when those other issues are solved?


Thanks for reviewing.  I was hoping this would be permanent as like
you noted these markers are really useful.

>

> I'm slightly concerned about all the different ways of controlling the

> text segment layout, but this seems like a good thing, and I'm not

> even sure why it shouldn't be on by default.


Agreed.

>

>> * 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.

>

> +  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)."));

>

> Don't put "(default)" in the help string -- bool options get this

> added automatically.

>

> This is OK with that fix. Thanks! (And sorry for the delay.)

>

> -cary
Jose E. Marchesi via Binutils March 7, 2018, 2:51 a.m. | #7
On Tue, Mar 6, 2018 at 6:35 PM, Sriraman Tallam <tmsriram@google.com> wrote:
> 6bly=

> ]ol lr6ub∞¬ø≠ºik m jjlknlgkubvgrf7tuvfrvc6wer`w


Sorry about this.  My son jumped on the keyboard :) and accidentally
hit send before I could even finish.

>

> On Tue, Mar 6, 2018 at 6:24 PM, Cary Coutant <ccoutant@gmail.com> wrote:

>>> 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.

>>

>> Are you thinking this is just going to be a temporary feature, to be

>> phased out when those other issues are solved?

>

> Thanks for reviewing.  I was hoping this would be permanent as like

> you noted these markers are really useful.


Also, there are two ways in which various subsets of text are mapped
to huge pages.  One is by going through the sections in a particular
segment and the other way is to map only one executable segment.  I
want to be able to support both.

>

>>

>> I'm slightly concerned about all the different ways of controlling the

>> text segment layout, but this seems like a good thing, and I'm not

>> even sure why it shouldn't be on by default.

>

> Agreed.

>

>>

>>> * 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.

>>

>> +  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)."));

>>

>> Don't put "(default)" in the help string -- bool options get this

>> added automatically.

>>

>> This is OK with that fix. Thanks! (And sorry for the delay.)

>>

>> -cary


Thanks
Sri
Jose E. Marchesi via Binutils March 20, 2018, 9:52 p.m. | #8
FYI, I have back-ported this to the binutils-2_29-branch.

Thanks
Sri


On Tue, Mar 6, 2018 at 6:51 PM Sriraman Tallam <tmsriram@google.com> wrote:

> On Tue, Mar 6, 2018 at 6:35 PM, Sriraman Tallam <tmsriram@google.com>

> wrote:

> > 6bly=

> > ]ol lr6ub∞¬ø≠ºik m jjlknlgkubvgrf7tuvfrvc6wer`w

>

> Sorry about this.  My son jumped on the keyboard :) and accidentally

> hit send before I could even finish.

>

> >

> > On Tue, Mar 6, 2018 at 6:24 PM, Cary Coutant <ccoutant@gmail.com> wrote:

> >>> 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.

> >>

> >> Are you thinking this is just going to be a temporary feature, to be

> >> phased out when those other issues are solved?

> >

> > Thanks for reviewing.  I was hoping this would be permanent as like

> > you noted these markers are really useful.

>

> Also, there are two ways in which various subsets of text are mapped

> to huge pages.  One is by going through the sections in a particular

> segment and the other way is to map only one executable segment.  I

> want to be able to support both.

>

> >

> >>

> >> I'm slightly concerned about all the different ways of controlling the

> >> text segment layout, but this seems like a good thing, and I'm not

> >> even sure why it shouldn't be on by default.

> >

> > Agreed.

> >

> >>

> >>> * 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.

> >>

> >> +  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)."));

> >>

> >> Don't put "(default)" in the help string -- bool options get this

> >> added automatically.

> >>

> >> This is OK with that fix. Thanks! (And sorry for the delay.)

> >>

> >> -cary

>

> Thanks

> Sri

>

Patch

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"