public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Support SHF_GNU_MBIND and PT_GNU_MBIND_XXX
@ 2017-03-15 22:46 H.J. Lu
  2017-03-17  3:38 ` Alan Modra
  0 siblings, 1 reply; 5+ messages in thread
From: H.J. Lu @ 2017-03-15 22:46 UTC (permalink / raw)
  To: binutils

Hi,

Here is a patch to support SHF_GNU_MBIND and PT_GNU_MBIND_XXX in as and
ld:

https://sourceware.org/ml/gnu-gabi/2017-q1/msg00016.html

Any comments?

Thanks.


H.J.
---
Mark an ALLOC section, which should be placed in special memory area,
with SHF_GNU_MBIND.  Its sh_info field indicates the special memory
type.  GNU_MBIND section names start with ".mbind" so that they are
placed as orphan sections by linker.  All input GNU_MBIND sections
with the same sh_type, sh_flags and sh_info are placed in one output
GNU_MBIND section.  In executable and shared object, create a
GNU_MBIND segment for each GNU_MBIND section and its segment type is
PT_GNU_MBIND_LO plus the sh_info value.  Each GNU_MBIND segment is
aligned at page boundary.

The assembler syntax:

    .section .mbind.foo,"adx",%progbits
                          ^             0: Special memory type.
                          |
                         'd' for SHF_GNU_MBIND.

    .section .mbind.foo,"adx",%progbits,0x1
                          ^             1: Special memory type.
                          |
                         'd' for SHF_GNU_MBIND.

    .section .mbind.bar,"adG",%progbits,.foo_group,comdat,0x2
                          ^                               2: Special memory type.
                          |
                         'd' for SHF_GNU_MBIND.

bfd/

	* elf.c (get_program_header_size): Add a GNU_MBIND segment for
	each GNU_MBIND section and align GNU_MBIND section to page size.
	(_bfd_elf_map_sections_to_segments): Create a GNU_MBIND
	segment for each GNU_MBIND section.
	(_bfd_elf_init_private_section_data): Copy sh_info from input
	for GNU_MBIND section.

binutils/

	* readelf.c (get_segment_type): Handle PT_GNU_MBIND_XXX.
	(get_elf_section_flags): Handle SHF_GNU_MBIND.
	(process_section_headers): Likewise.

gas/

	* config/obj-elf.c (section_match): New.
	(get_section): Match both sh_info and group name.
	(obj_elf_change_section): Add argument for sh_info.  Pass both
	sh_info and group name to get_section. Issue an error for
	SHF_GNU_MBIND section without SHF_ALLOC.  Set sh_info.
	(obj_elf_parse_section_letters): Set SHF_GNU_MBIND for 'd'.
	(obj_elf_section): Support SHF_GNU_MBIND section info.
	* config/obj-elf.h (obj_elf_change_section): Add argument for
	sh_info.
	* config/tc-arm.c (start_unwind_section): Pass 0 as sh_info to
	obj_elf_change_section.
	* config/tc-ia64.c (obj_elf_vms_common): Likewise.
	* config/tc-microblaze.c (microblaze_s_data): Likewise.
	(microblaze_s_sdata): Likewise.
	(microblaze_s_rdata): Likewise.
	(microblaze_s_bss): Likewise.
	* config/tc-mips.c (s_change_section): Likewise.
	* config/tc-msp430.c (msp430_profiler): Likewise.
	* config/tc-rx.c (parse_rx_section): Likewise.
	* config/tc-tic6x.c (tic6x_start_unwind_section): Likewise.
	* testsuite/gas/elf/elf.exp: Run section12a, section12b and
	section13.
	* testsuite/gas/elf/section10.d: Updated.
	* testsuite/gas/elf/section10.s: Likewise.
	* testsuite/gas/elf/section12.s: New file.
	* testsuite/gas/elf/section12a.d: Likewise.
	* testsuite/gas/elf/section12b.d: Likewise.
	* testsuite/gas/elf/section13.l: New file.
	* testsuite/gas/elf/section13.d: New file.
	* testsuite/gas/elf/section13.s: New file.

include/

	elf/common.h (PT_GNU_MBIND_NUM): New.
	(PT_GNU_MBIND_LO): Likewise.
	(PT_GNU_MBIND_HI): Likewise.
	(SHF_GNU_MBIND): Likewise.

ld/

	* emultempl/elf32.em (gld${EMULATION_NAME}_place_orphan): Place
	input GNU_MBIND sections with the same type, attributes and
	sh_info field into a single output GNU_MBIND section.
	* testsuite/ld-elf/elf.exp: Run mbind2a and mbind2b.
	* testsuite/ld-elf/mbind1.s: New file.
	* testsuite/ld-elf/mbind1a.d: Likewise.
	* testsuite/ld-elf/mbind1b.d: Likewise.
	* testsuite/ld-elf/mbind1c.d: Likewise.
	* testsuite/ld-elf/mbind2a.s: Likewise.
	* testsuite/ld-elf/mbind2b.c: Likewise.
---
 bfd/elf.c                          | 66 ++++++++++++++++++++++++++++++++++++--
 binutils/readelf.c                 | 17 ++++++++--
 gas/config/obj-elf.c               | 54 +++++++++++++++++++++++++++----
 gas/config/obj-elf.h               |  3 +-
 gas/config/tc-arm.c                |  3 +-
 gas/config/tc-ia64.c               |  2 +-
 gas/config/tc-microblaze.c         | 18 +++++++----
 gas/config/tc-mips.c               |  2 +-
 gas/config/tc-msp430.c             |  2 +-
 gas/config/tc-rx.c                 |  4 +--
 gas/config/tc-tic6x.c              |  3 +-
 gas/testsuite/gas/elf/elf.exp      |  3 ++
 gas/testsuite/gas/elf/section10.d  |  4 +--
 gas/testsuite/gas/elf/section10.s  |  4 +--
 gas/testsuite/gas/elf/section12.s  | 33 +++++++++++++++++++
 gas/testsuite/gas/elf/section12a.d | 35 ++++++++++++++++++++
 gas/testsuite/gas/elf/section12b.d | 32 ++++++++++++++++++
 gas/testsuite/gas/elf/section13.d  |  2 ++
 gas/testsuite/gas/elf/section13.l  |  2 ++
 gas/testsuite/gas/elf/section13.s  |  2 ++
 include/elf/common.h               |  7 ++++
 ld/emultempl/elf32.em              | 46 +++++++++++++++++++++++++-
 ld/testsuite/ld-elf/elf.exp        | 21 ++++++++++++
 ld/testsuite/ld-elf/mbind1.s       | 43 +++++++++++++++++++++++++
 ld/testsuite/ld-elf/mbind1a.d      | 44 +++++++++++++++++++++++++
 ld/testsuite/ld-elf/mbind1b.d      | 44 +++++++++++++++++++++++++
 ld/testsuite/ld-elf/mbind1c.d      | 44 +++++++++++++++++++++++++
 ld/testsuite/ld-elf/mbind2a.s      | 15 +++++++++
 ld/testsuite/ld-elf/mbind2b.c      | 17 ++++++++++
 29 files changed, 541 insertions(+), 31 deletions(-)
 create mode 100644 gas/testsuite/gas/elf/section12.s
 create mode 100644 gas/testsuite/gas/elf/section12a.d
 create mode 100644 gas/testsuite/gas/elf/section12b.d
 create mode 100644 gas/testsuite/gas/elf/section13.d
 create mode 100644 gas/testsuite/gas/elf/section13.l
 create mode 100644 gas/testsuite/gas/elf/section13.s
 create mode 100644 ld/testsuite/ld-elf/mbind1.s
 create mode 100644 ld/testsuite/ld-elf/mbind1a.d
 create mode 100644 ld/testsuite/ld-elf/mbind1b.d
 create mode 100644 ld/testsuite/ld-elf/mbind1c.d
 create mode 100644 ld/testsuite/ld-elf/mbind2a.s
 create mode 100644 ld/testsuite/ld-elf/mbind2b.c

diff --git a/bfd/elf.c b/bfd/elf.c
index 9418e51..3cddfe0 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -4330,9 +4330,33 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
 	}
     }
 
-  /* Let the backend count up any program headers it might need.  */
   bed = get_elf_backend_data (abfd);
-  if (bed->elf_backend_additional_program_headers)
+
+ if ((abfd->flags & D_PAGED) != 0)
+   {
+     /* Add a PT_GNU_MBIND segment for each mbind section.  */
+     unsigned int page_align_power = bfd_log2 (bed->commonpagesize);
+     for (s = abfd->sections; s != NULL; s = s->next)
+       if (elf_section_flags (s) & SHF_GNU_MBIND)
+	 {
+	   if (elf_section_data (s)->this_hdr.sh_info
+	       > PT_GNU_MBIND_NUM)
+	     {
+	       _bfd_error_handler
+		 /* xgettext:c-format */
+		 (_("%B: GNU_MBIN section `%A' has invalid sh_info field: %d"),
+		     abfd, s, elf_section_data (s)->this_hdr.sh_info);
+	       continue;
+	     }
+	   /* Align mbind section to page size.  */
+	   if (s->alignment_power < page_align_power)
+	     s->alignment_power = page_align_power;
+	   segs ++;
+	 }
+   }
+
+ /* Let the backend count up any program headers it might need.  */
+ if (bed->elf_backend_additional_program_headers)
     {
       int a;
 
@@ -4504,6 +4528,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       bfd_boolean writable;
       int tls_count = 0;
       asection *first_tls = NULL;
+      asection *first_mbind = NULL;
       asection *dynsec, *eh_frame_hdr;
       bfd_size_type amt;
       bfd_vma addr_mask, wrap_to = 0;
@@ -4836,6 +4861,9 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
 		first_tls = s;
 	      tls_count++;
 	    }
+	  if (first_mbind == NULL
+	      && (elf_section_flags (s) & SHF_GNU_MBIND) != 0)
+	    first_mbind = s;
 	}
 
       /* If there are any SHF_TLS output sections, add PT_TLS segment.  */
@@ -4883,6 +4911,35 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
 	  pm = &m->next;
 	}
 
+      if (first_mbind && (abfd->flags & D_PAGED) != 0)
+	for (s = first_mbind; s != NULL; s = s->next)
+	  if ((elf_section_flags (s) & SHF_GNU_MBIND) != 0
+	      && (elf_section_data (s)->this_hdr.sh_info
+		  <= PT_GNU_MBIND_NUM))
+	    {
+	      /* Mandated PF_R.  */
+	      unsigned long p_flags = PF_R;
+	      if ((s->flags & SEC_READONLY) == 0)
+		p_flags |= PF_W;
+	      if ((s->flags & SEC_CODE) != 0)
+		p_flags |= PF_X;
+
+	      amt = sizeof (struct elf_segment_map) + sizeof (asection *);
+	      m = bfd_zalloc (abfd, amt);
+	      if (m == NULL)
+		goto error_return;
+	      m->next = NULL;
+	      m->p_type = (PT_GNU_MBIND_LO
+			   + elf_section_data (s)->this_hdr.sh_info);
+	      m->count = 1;
+	      m->p_flags_valid = 1;
+	      m->sections[0] = s;
+	      m->p_flags = p_flags;
+
+	      *pm = m;
+	      pm = &m->next;
+	    }
+
       /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME
 	 segment.  */
       eh_frame_hdr = elf_eh_frame_hdr (abfd);
@@ -7359,6 +7416,11 @@ _bfd_elf_init_private_section_data (bfd *ibfd,
   elf_section_flags (osec) |= (elf_section_flags (isec)
 			       & (SHF_MASKOS | SHF_MASKPROC));
 
+  /* Copy sh_info from input for mbind section.  */
+  if (elf_section_flags (isec) & SHF_GNU_MBIND)
+    elf_section_data (osec)->this_hdr.sh_info
+      = elf_section_data (isec)->this_hdr.sh_info;
+
   /* Set things up for objcopy and relocatable link.  The output
      SHT_GROUP section will have its elf_next_in_group pointing back
      to the input group members.  Ignore linker created group section.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 34781ae..b0be6fd 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -3819,7 +3819,12 @@ get_segment_type (unsigned long p_type)
     case PT_GNU_RELRO:  return "GNU_RELRO";
 
     default:
-      if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
+      if (p_type >= PT_GNU_MBIND_LO && p_type <= PT_GNU_MBIND_HI)
+	{
+	  sprintf (buff, "GNU_MBIND+%#lx",
+		   p_type - PT_GNU_MBIND_LO);
+	}
+      else if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
 	{
 	  const char * result;
 
@@ -5524,7 +5529,9 @@ get_elf_section_flags (bfd_vma sh_flags)
       /* ARM specific.  */
       /* 21 */ { STRING_COMMA_LEN ("ENTRYSECT") },
       /* 22 */ { STRING_COMMA_LEN ("ARM_PURECODE") },
-      /* 23 */ { STRING_COMMA_LEN ("COMDEF") }
+      /* 23 */ { STRING_COMMA_LEN ("COMDEF") },
+      /* GNU specific.  */
+      /* 24 */ { STRING_COMMA_LEN ("GNU_MBIND") },
     };
 
   if (do_section_details)
@@ -5557,6 +5564,7 @@ get_elf_section_flags (bfd_vma sh_flags)
 	    case SHF_TLS:		sindex = 9; break;
 	    case SHF_EXCLUDE:		sindex = 18; break;
 	    case SHF_COMPRESSED:	sindex = 20; break;
+	    case SHF_GNU_MBIND:		sindex = 24; break;
 
 	    default:
 	      sindex = -1;
@@ -5650,6 +5658,7 @@ get_elf_section_flags (bfd_vma sh_flags)
 	    case SHF_TLS:		*p = 'T'; break;
 	    case SHF_EXCLUDE:		*p = 'E'; break;
 	    case SHF_COMPRESSED:	*p = 'C'; break;
+	    case SHF_GNU_MBIND:		*p = 'D'; break;
 
 	    default:
 	      if ((elf_header.e_machine == EM_X86_64
@@ -6178,7 +6187,9 @@ process_section_headers (FILE * file)
 	      if (section->sh_info < 1 || section->sh_info >= elf_header.e_shnum)
 		warn (_("[%2u]: Expected link to another section in info field"), i);
 	    }
-	  else if (section->sh_type < SHT_LOOS && section->sh_info != 0)
+	  else if (section->sh_type < SHT_LOOS
+		   && (section->sh_flags & SHF_GNU_MBIND) == 0
+		   && section->sh_info != 0)
 	    warn (_("[%2u]: Unexpected value (%u) in info field.\n"),
 		  i, section->sh_info);
 	  break;
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index 1d59fc0..3696d5e 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -520,16 +520,26 @@ struct section_stack
 
 static struct section_stack *section_stack;
 
+/* Match both section group name and the sh_info field.  */
+struct section_match
+{
+  const char *group_name;
+  unsigned int info;
+};
+
 static bfd_boolean
 get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 {
-  const char *gname = (const char *) inf;
+  struct section_match *match = (struct section_match *) inf;
+  const char *gname = match->group_name;
   const char *group_name = elf_group_name (sec);
+  unsigned int info = elf_section_data (sec)->this_hdr.sh_info;
 
-  return (group_name == gname
-	  || (group_name != NULL
-	      && gname != NULL
-	      && strcmp (group_name, gname) == 0));
+  return (info == match->info
+	  && (group_name == gname
+	      || (group_name != NULL
+		  && gname != NULL
+		  && strcmp (group_name, gname) == 0)));
 }
 
 /* Handle the .section pseudo-op.  This code supports two different
@@ -553,6 +563,7 @@ get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 void
 obj_elf_change_section (const char *name,
 			unsigned int type,
+			unsigned int info,
 			bfd_vma attr,
 			int entsize,
 			const char *group_name,
@@ -564,6 +575,7 @@ obj_elf_change_section (const char *name,
   flagword flags;
   const struct elf_backend_data *bed;
   const struct bfd_elf_special_section *ssect;
+  struct section_match match;
 
 #ifdef md_flush_pending_output
   md_flush_pending_output ();
@@ -584,8 +596,10 @@ obj_elf_change_section (const char *name,
   previous_section = now_seg;
   previous_subsection = now_subseg;
 
+  match.group_name = group_name;
+  match.info = info;
   old_sec = bfd_get_section_by_name_if (stdoutput, name, get_section,
-					(void *) group_name);
+					(void *) &match);
   if (old_sec)
     {
       sec = old_sec;
@@ -695,6 +709,9 @@ obj_elf_change_section (const char *name,
 	attr |= ssect->attr;
     }
 
+  if ((attr & (SHF_ALLOC | SHF_GNU_MBIND)) == SHF_GNU_MBIND)
+    as_fatal (_("SHF_ALLOC isn't set for GNU_MBIND section: %s"), name);
+
   /* Convert ELF type and flags to BFD flags.  */
   flags = (SEC_RELOC
 	   | ((attr & SHF_WRITE) ? 0 : SEC_READONLY)
@@ -720,6 +737,7 @@ obj_elf_change_section (const char *name,
 	type = bfd_elf_get_default_section_type (flags);
       elf_section_type (sec) = type;
       elf_section_flags (sec) = attr;
+      elf_section_data (sec)->this_hdr.sh_info = info;
 
       /* Prevent SEC_HAS_CONTENTS from being inadvertently set.  */
       if (type == SHT_NOBITS)
@@ -803,6 +821,9 @@ obj_elf_parse_section_letters (char *str, size_t len, bfd_boolean *is_clone)
 	case 'T':
 	  attr |= SHF_TLS;
 	  break;
+	case 'd':
+	  attr |= SHF_GNU_MBIND;
+	  break;
 	case '?':
 	  *is_clone = TRUE;
 	  break;
@@ -996,6 +1017,7 @@ obj_elf_section (int push)
   int entsize;
   int linkonce;
   subsegT new_subsection = -1;
+  unsigned int info = 0;
 
 #ifndef TC_I370
   if (flag_mri)
@@ -1159,6 +1181,23 @@ obj_elf_section (int push)
 		  linkonce = (now_seg->flags & SEC_LINK_ONCE) != 0;
 		}
 	    }
+
+	  if ((attr & SHF_GNU_MBIND) != 0 && *input_line_pointer == ',')
+	    {
+	      ++input_line_pointer;
+	      SKIP_WHITESPACE ();
+	      if (ISDIGIT (* input_line_pointer))
+		{
+		  char *t = input_line_pointer;
+		  info = strtoul (input_line_pointer,
+				  &input_line_pointer, 0);
+		  if (info == (unsigned int) -1)
+		    {
+		      as_warn (_("unsupported mbind section info: %s"), t);
+		      info = 0;
+		    }
+		}
+	    }
 	}
       else
 	{
@@ -1189,7 +1228,8 @@ obj_elf_section (int push)
 done:
   demand_empty_rest_of_line ();
 
-  obj_elf_change_section (name, type, attr, entsize, group_name, linkonce, push);
+  obj_elf_change_section (name, type, info, attr, entsize, group_name,
+			  linkonce, push);
 
   if (push && new_subsection != -1)
     subseg_set (now_seg, new_subsection);
diff --git a/gas/config/obj-elf.h b/gas/config/obj-elf.h
index f6bd216..37d6aee 100644
--- a/gas/config/obj-elf.h
+++ b/gas/config/obj-elf.h
@@ -162,7 +162,8 @@ extern void obj_elf_common (int);
 extern void obj_elf_data (int);
 extern void obj_elf_text (int);
 extern void obj_elf_change_section
-  (const char *, unsigned int, bfd_vma, int, const char *, int, int);
+  (const char *, unsigned int, unsigned int, bfd_vma, int, const char *,
+   int, int);
 extern struct fix *obj_elf_vtable_inherit (int);
 extern struct fix *obj_elf_vtable_entry (int);
 extern bfd_boolean obj_elf_seen_attribute
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index a433929..743fcfc 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -22113,7 +22113,8 @@ start_unwind_section (const segT text_seg, int idx)
       linkonce = 1;
     }
 
-  obj_elf_change_section (sec_name, type, flags, 0, group_name, linkonce, 0);
+  obj_elf_change_section (sec_name, type, 0, flags, 0, group_name,
+			  linkonce, 0);
 
   /* Set the section link for index tables.  */
   if (idx)
diff --git a/gas/config/tc-ia64.c b/gas/config/tc-ia64.c
index aa01eff..e236dd5 100644
--- a/gas/config/tc-ia64.c
+++ b/gas/config/tc-ia64.c
@@ -1139,7 +1139,7 @@ obj_elf_vms_common (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 
   obj_elf_change_section
-    (sec_name, SHT_NOBITS,
+    (sec_name, SHT_NOBITS, 0,
      SHF_ALLOC | SHF_WRITE | SHF_IA_64_VMS_OVERLAID | SHF_IA_64_VMS_GLOBAL,
      0, NULL, 1, 0);
 
diff --git a/gas/config/tc-microblaze.c b/gas/config/tc-microblaze.c
index c3b091f..0124422 100644
--- a/gas/config/tc-microblaze.c
+++ b/gas/config/tc-microblaze.c
@@ -145,7 +145,8 @@ static void
 microblaze_s_data (int ignore ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_ELF
-  obj_elf_change_section (".data", SHT_PROGBITS, SHF_ALLOC+SHF_WRITE, 0, 0, 0, 0);
+  obj_elf_change_section (".data", SHT_PROGBITS, 0, SHF_ALLOC+SHF_WRITE,
+			  0, 0, 0, 0);
 #else
   s_data (ignore);
 #endif
@@ -157,7 +158,8 @@ static void
 microblaze_s_sdata (int ignore ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_ELF
-  obj_elf_change_section (".sdata", SHT_PROGBITS, SHF_ALLOC+SHF_WRITE, 0, 0, 0, 0);
+  obj_elf_change_section (".sdata", SHT_PROGBITS, 0, SHF_ALLOC+SHF_WRITE,
+			  0, 0, 0, 0);
 #else
   s_data (ignore);
 #endif
@@ -275,14 +277,16 @@ microblaze_s_rdata (int localvar)
   if (localvar == 0)
     {
       /* rodata.  */
-      obj_elf_change_section (".rodata", SHT_PROGBITS, SHF_ALLOC, 0, 0, 0, 0);
+      obj_elf_change_section (".rodata", SHT_PROGBITS, 0, SHF_ALLOC,
+			      0, 0, 0, 0);
       if (rodata_segment == 0)
 	rodata_segment = subseg_new (".rodata", 0);
     }
   else
     {
       /* 1 .sdata2.  */
-      obj_elf_change_section (".sdata2", SHT_PROGBITS, SHF_ALLOC, 0, 0, 0, 0);
+      obj_elf_change_section (".sdata2", SHT_PROGBITS, 0, SHF_ALLOC,
+			      0, 0, 0, 0);
     }
 #else
   s_data (ignore);
@@ -294,11 +298,13 @@ microblaze_s_bss (int localvar)
 {
 #ifdef OBJ_ELF
   if (localvar == 0) /* bss.  */
-    obj_elf_change_section (".bss", SHT_NOBITS, SHF_ALLOC+SHF_WRITE, 0, 0, 0, 0);
+    obj_elf_change_section (".bss", SHT_NOBITS, 0, SHF_ALLOC+SHF_WRITE,
+			    0, 0, 0, 0);
   else if (localvar == 1)
     {
       /* sbss.  */
-      obj_elf_change_section (".sbss", SHT_NOBITS, SHF_ALLOC+SHF_WRITE, 0, 0, 0, 0);
+      obj_elf_change_section (".sbss", SHT_NOBITS, 0, SHF_ALLOC+SHF_WRITE,
+			      0, 0, 0, 0);
       if (sbss_segment == 0)
 	sbss_segment = subseg_new (".sbss", 0);
     }
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 54b94be..6a98122 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -15879,7 +15879,7 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
   if (section_type == SHT_MIPS_DWARF)
     section_type = SHT_PROGBITS;
 
-  obj_elf_change_section (section_name, section_type, section_flag,
+  obj_elf_change_section (section_name, section_type, 0, section_flag,
 			  section_entry_size, 0, 0, 0);
 
   if (now_seg->name != section_name)
diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c
index a24771b..10e5972 100644
--- a/gas/config/tc-msp430.c
+++ b/gas/config/tc-msp430.c
@@ -612,7 +612,7 @@ msp430_profiler (int dummy ATTRIBUTE_UNUSED)
   subseg = now_subseg;
 
   /* Now go to .profiler section.  */
-  obj_elf_change_section (".profiler", SHT_PROGBITS, 0, 0, 0, 0, 0);
+  obj_elf_change_section (".profiler", SHT_PROGBITS, 0, 0, 0, 0, 0, 0);
 
   /* Save flags.  */
   emit_expr (& exp, 2);
diff --git a/gas/config/tc-rx.c b/gas/config/tc-rx.c
index 05fa4da..ba826c7 100644
--- a/gas/config/tc-rx.c
+++ b/gas/config/tc-rx.c
@@ -486,7 +486,7 @@ parse_rx_section (char * name)
       else
 	type = SHT_NOBITS;
 
-      obj_elf_change_section (name, type, attr, 0, NULL, FALSE, FALSE);
+      obj_elf_change_section (name, type, 0, attr, 0, NULL, FALSE, FALSE);
     }
   else /* Try not to redefine a section, especially B_1.  */
     {
@@ -501,7 +501,7 @@ parse_rx_section (char * name)
 	| ((flags & SEC_STRINGS) ? SHF_STRINGS : 0)
 	| ((flags & SEC_THREAD_LOCAL) ? SHF_TLS : 0);
 
-      obj_elf_change_section (name, type, attr, 0, NULL, FALSE, FALSE);
+      obj_elf_change_section (name, type, 0, attr, 0, NULL, FALSE, FALSE);
     }
 
   bfd_set_section_alignment (stdoutput, now_seg, align);
diff --git a/gas/config/tc-tic6x.c b/gas/config/tc-tic6x.c
index c75fcf6..6958a0e 100644
--- a/gas/config/tc-tic6x.c
+++ b/gas/config/tc-tic6x.c
@@ -4666,7 +4666,8 @@ tic6x_start_unwind_section (const segT text_seg, int idx)
       linkonce = 1;
     }
 
-  obj_elf_change_section (sec_name, type, flags, 0, group_name, linkonce, 0);
+  obj_elf_change_section (sec_name, type, 0, flags, 0, group_name,
+			  linkonce, 0);
 
   /* Set the section link for index tables.  */
   if (idx)
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index e4dd684..2a1bb27 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -209,6 +209,9 @@ if { [is_elf_format] } then {
     run_dump_test "section9"
     run_dump_test "section10"
     run_dump_test "section11"
+    run_dump_test "section12a"
+    run_dump_test "section12b"
+    run_dump_test "section13"
     run_dump_test "dwarf2-1"
     run_dump_test "dwarf2-2"
     run_dump_test "dwarf2-3"
diff --git a/gas/testsuite/gas/elf/section10.d b/gas/testsuite/gas/elf/section10.d
index aa5ca3c..e187263 100644
--- a/gas/testsuite/gas/elf/section10.d
+++ b/gas/testsuite/gas/elf/section10.d
@@ -18,7 +18,7 @@
 #...
 [ 	]*\[.*\][ 	]+sec3
 [ 	]*PROGBITS.*
-[ 	]*\[.*ffff030\]: MERGE, STRINGS,.* EXCLUDE, OS \(.*ff00000\), PROC \(.*[347]0000000\), UNKNOWN \(0+0ff000\)
+[ 	]*\[.*fefff030\]: MERGE, STRINGS,.* EXCLUDE, OS \(.*ef00000\), PROC \(.*[347]0000000\), UNKNOWN \(0+0ff000\)
 #...
 [ 	]*\[.*\][ 	]+sec4
 [ 	]*LOOS\+0x11[ 	].*
@@ -26,7 +26,7 @@
 #...
 [ 	]*\[.*\][ 	]+sec5
 [ 	]*LOUSER\+0x9[ 	].*
-[ 	]*\[.*fff0000\]:.* EXCLUDE, OS \(.*ff00000\), PROC \(.*[347]0000000\), UNKNOWN \(.*f0000\)
+[ 	]*\[.*feff0000\]:.* EXCLUDE, OS \(.*ef00000\), PROC \(.*[347]0000000\), UNKNOWN \(.*f0000\)
 [ 	]*\[.*\][ 	]+.data.foo
 [ 	]*LOUSER\+0x7f000000[ 	].*
 [ 	]*\[0+003\]: WRITE, ALLOC
diff --git a/gas/testsuite/gas/elf/section10.s b/gas/testsuite/gas/elf/section10.s
index 0576007..29f1184 100644
--- a/gas/testsuite/gas/elf/section10.s
+++ b/gas/testsuite/gas/elf/section10.s
@@ -7,7 +7,7 @@
 	.word 2
 
 	# Make sure that specifying further arguments to .sections is still supported
-	.section sec3, "0xfffff000MS", %progbits, 32
+	.section sec3, "0xfefff000MS", %progbits, 32
 	.word 3
 
 	# Make sure that extra flags can be set for well known sections as well.
@@ -19,7 +19,7 @@
 	.word 5
 
 	# Test both together, with a quoted type value.
-	.section sec5, "0xffff0000", "0x80000009"
+	.section sec5, "0xfeff0000", "0x80000009"
 	.word 6
 
 	# Test that declaring an extended version of a known special section works.
diff --git a/gas/testsuite/gas/elf/section12.s b/gas/testsuite/gas/elf/section12.s
new file mode 100644
index 0000000..41faad4
--- /dev/null
+++ b/gas/testsuite/gas/elf/section12.s
@@ -0,0 +1,33 @@
+	.section .mbind.data,"adw",%progbits
+	.byte 1
+
+	.section .mbind.data,"adw",%progbits,0x3
+	.byte 2
+
+	.section .mbind.text,"adx",%progbits
+	.byte 3
+
+	.section .mbind.text,"adx",%progbits,0x3
+	.byte 4
+
+	.section .mbind.bss,"adw",%nobits
+	.zero 5
+
+	.section .mbind.bss,"adw",%nobits,0x3
+	.zero 6
+
+	.section .mbind.rodata,"adG",%progbits,.foo_group,comdat,0x2
+	.byte 7
+
+	.section .mbind.data,"adGw",%progbits,.foo_group,comdat
+	.byte 8
+
+	.section .mbind.data,"adGw",%progbits,.foo_group,comdat,0x3
+	.byte 9
+
+	# Check that .pushsection works as well.
+	.pushsection .mbind.text,"adGx",%progbits,.foo_group,comdat,0x3
+	.byte 10
+
+	.popsection
+	.byte 11
diff --git a/gas/testsuite/gas/elf/section12a.d b/gas/testsuite/gas/elf/section12a.d
new file mode 100644
index 0000000..d31a675
--- /dev/null
+++ b/gas/testsuite/gas/elf/section12a.d
@@ -0,0 +1,35 @@
+#source: section12.s
+#as: --no-pad-sections
+#readelf: -Sg --wide
+#name: mbind sections
+# The RX port annoyingly reorders the sections so that they do not match the sequence expected below.
+#skip: rx-*-*
+
+#...
+  \[[ 0-9]+\] \.mbind\.data[ 	]+PROGBITS[ 	]+0+0 0+[0-9a-f]+ 0+1 00 WAD  0   0  1
+#...
+  \[[ 0-9]+\] \.mbind\.data[ 	]+PROGBITS[ 	]+0+0 0+[0-9a-f]+ 0+1 00 WAD  0   3  1
+#...
+  \[[ 0-9]+\] \.mbind\.text[ 	]+PROGBITS[ 	]+0+0 0+[0-9a-f]+ 0+1 00 AXD  0   0  1
+#...
+  \[[ 0-9]+\] \.mbind\.text[ 	]+PROGBITS[ 	]+0+0 0+[0-9a-f]+ 0+1 00 AXD  0   3  1
+#...
+  \[[ 0-9]+\] \.mbind\.bss[ 	]+NOBITS[ 	]+0+0 0+[0-9a-f]+ 0+5 00 WAD  0   0  1
+#...
+  \[[ 0-9]+\] \.mbind\.bss[ 	]+NOBITS[ 	]+0+0 0+[0-9a-f]+ 0+6 00 WAD  0   3  1
+#...
+  \[[ 0-9]+\] \.mbind\.rodata[ 	]+PROGBITS[ 	]+0+0 0+[0-9a-f]+ 0+1 00 AGD  0   2  1
+#...
+  \[[ 0-9]+\] \.mbind\.data[ 	]+PROGBITS[ 	]+0+0 0+[0-9a-f]+ 0+1 00 WAGD  0   0  1
+#...
+  \[[ 0-9]+\] \.mbind\.data[ 	]+PROGBITS[ 	]+0+0 0+[0-9a-f]+ 0+2 00 WAGD  0   3  1
+#...
+  \[[ 0-9]+\] \.mbind\.text[ 	]+PROGBITS[ 	]+0+0 0+[0-9a-f]+ 0+1 00 AXGD  0   3  1
+#...
+COMDAT group section \[    1\] `\.group' \[\.foo_group\] contains 4 sections:
+[ 	]+\[Index\][ 	]+Name
+[ 	]+\[[ 0-9]+][ 	]+\.mbind\.rodata
+[ 	]+\[[ 0-9]+][ 	]+\.mbind\.data
+[ 	]+\[[ 0-9]+][ 	]+\.mbind\.data
+[ 	]+\[[ 0-9]+][ 	]+\.mbind\.text
+#pass
diff --git a/gas/testsuite/gas/elf/section12b.d b/gas/testsuite/gas/elf/section12b.d
new file mode 100644
index 0000000..717bc1a
--- /dev/null
+++ b/gas/testsuite/gas/elf/section12b.d
@@ -0,0 +1,32 @@
+#source: section12.s
+#as: --no-pad-sections
+#objdump: -s
+#name: mbind section contents
+# The RX port annoyingly reorders the sections so that they do not match the sequence expected below.
+#skip: rx-*-*
+
+#...
+Contents of section .mbind.data:
+ 0000 01                                   .               
+#...
+Contents of section .mbind.data:
+ 0000 02                                   .               
+#...
+Contents of section .mbind.text:
+ 0000 03                                   .               
+#...
+Contents of section .mbind.text:
+ 0000 04                                   .               
+#...
+Contents of section .mbind.rodata:
+ 0000 07                                   .               
+#...
+Contents of section .mbind.data:
+ 0000 08                                   .               
+#...
+Contents of section .mbind.data:
+ 0000 090b                                 ..              
+#...
+Contents of section .mbind.text:
+ 0000 0a                                   .               
+#pass
diff --git a/gas/testsuite/gas/elf/section13.d b/gas/testsuite/gas/elf/section13.d
new file mode 100644
index 0000000..3ee7c82
--- /dev/null
+++ b/gas/testsuite/gas/elf/section13.d
@@ -0,0 +1,2 @@
+#name: mbind sections without SHF_ALLOC
+#error-output: section13.l
diff --git a/gas/testsuite/gas/elf/section13.l b/gas/testsuite/gas/elf/section13.l
new file mode 100644
index 0000000..c56b5ae
--- /dev/null
+++ b/gas/testsuite/gas/elf/section13.l
@@ -0,0 +1,2 @@
+[^:]*: Assembler messages:
+[^:]*:1: Fatal error: SHF_ALLOC isn't set for GNU_MBIND section: .mbind.data
diff --git a/gas/testsuite/gas/elf/section13.s b/gas/testsuite/gas/elf/section13.s
new file mode 100644
index 0000000..6630f35
--- /dev/null
+++ b/gas/testsuite/gas/elf/section13.s
@@ -0,0 +1,2 @@
+	.section .mbind.data,"dw",@nobits
+	.byte 0
diff --git a/include/elf/common.h b/include/elf/common.h
index 8888a55..78df476 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -460,6 +460,11 @@
 #define PT_GNU_STACK	(PT_LOOS + 0x474e551) /* Stack flags */
 #define PT_GNU_RELRO	(PT_LOOS + 0x474e552) /* Read-only after relocation */
 
+/* Mbind segments */
+#define PT_GNU_MBIND_NUM 4096
+#define PT_GNU_MBIND_LO (PT_LOOS + 0x474e555)
+#define PT_GNU_MBIND_HI (PT_GNU_MBIND_LO + PT_GNU_MBIND_NUM - 1)
+
 /* Program segment permissions, in program header p_flags field.  */
 
 #define PF_X		(1 << 0)	/* Segment is executable */
@@ -543,6 +548,8 @@
 					   are not to be further
 					   relocated.  */
 
+#define SHF_GNU_MBIND	0x01000000	/* Mbind section.  */
+
 /* Compression types.  */
 #define ELFCOMPRESS_ZLIB   1		/* Compressed with zlib.  */
 #define ELFCOMPRESS_LOOS   0x60000000	/* OS-specific semantics, lo */
diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index d4837d0..a2378ae 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -2091,6 +2091,47 @@ gld${EMULATION_NAME}_place_orphan (asection *s,
 	}
     }
 
+  if (!bfd_link_relocatable (&link_info)
+      && (s->flags & SEC_ALLOC) != 0
+      && (elf_section_flags (s) & SHF_GNU_MBIND) != 0)
+    {
+      /* Find the output mbind section with the same type, attributes
+	 and sh_info field.  */
+      for (os = &lang_output_section_statement.head->output_section_statement;
+	   os != NULL;
+	   os = os->next)
+	if (os->bfd_section != NULL
+	    && !bfd_is_abs_section (os->bfd_section)
+	    && (elf_section_flags (os->bfd_section) & SHF_GNU_MBIND) != 0
+	    && ((s->flags & (SEC_ALLOC
+			     | SEC_LOAD
+			     | SEC_HAS_CONTENTS
+			     | SEC_READONLY
+			     | SEC_CODE))
+		== (os->bfd_section->flags & (SEC_ALLOC
+					      | SEC_LOAD
+					      | SEC_HAS_CONTENTS
+					      | SEC_READONLY
+					      | SEC_CODE)))
+	    && (elf_section_data (os->bfd_section)->this_hdr.sh_info
+		== elf_section_data (s)->this_hdr.sh_info))
+	    {
+	      lang_add_section (&os->children, s, NULL, os);
+	      return os;
+	    }
+
+      /* Create the output mbind section with the ".mbind." prefix
+	 in section name.  */
+      if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+	secname = ".mbind.bss";
+      else if ((s->flags & SEC_READONLY) == 0)
+	secname = ".mbind.data";
+      else if ((s->flags & SEC_CODE) == 0)
+	secname = ".mbind.rodata";
+      else
+	secname = ".mbind.text";
+    }
+
   /* Look through the script to see where to place this section.  */
   if (constraint == 0)
     for (os = lang_output_section_find (secname);
@@ -2103,8 +2144,11 @@ gld${EMULATION_NAME}_place_orphan (asection *s,
 
 	/* SEC_EXCLUDE is cleared when doing a relocatable link.  But
 	   we can't merge 2 input sections with the same name when only
-	   one of them has SHF_EXCLUDE.  */
+	   one of them has SHF_EXCLUDE.  Don't merge 2 sections with
+	   different sh_info.  */
 	if (os->bfd_section != NULL
+	    && (elf_section_data (os->bfd_section)->this_hdr.sh_info
+		== elf_section_data (s)->this_hdr.sh_info)
 	    && (os->bfd_section->flags == 0
 		|| ((!bfd_link_relocatable (&link_info)
 		     || (iself && (((elf_section_flags (s)
diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp
index 09c9dda..f889070 100644
--- a/ld/testsuite/ld-elf/elf.exp
+++ b/ld/testsuite/ld-elf/elf.exp
@@ -298,6 +298,27 @@ if { [istarget *-*-linux*]
      || [istarget *-*-nacl*]
      || [istarget *-*-gnu*] } {
     run_ld_link_exec_tests $array_tests_pie $xfails
+
+    run_ld_link_exec_tests [list \
+	[list \
+	    "Run mbind2a" \
+	    "$NOPIE_LDFLAGS -Wl,-z,common-page-size=0x4000" \
+	    "" \
+	    { mbind2a.s mbind2b.c } \
+	    "mbind2a" \
+	    "pass.out" \
+	    "-O2 -I../bfd" \
+	] \
+	[list \
+	    "Run mbind2b" \
+	    "-static -Wl,-z,common-page-size=0x4000" \
+	    "" \
+	    { mbind2a.s mbind2b.c } \
+	    "mbind2b" \
+	    "pass.out" \
+	    "-O2 -I../bfd" \
+	] \
+    ]
 }
 
 # <http://www.gnu.org/software/hurd/open_issues/binutils.html#static>
diff --git a/ld/testsuite/ld-elf/mbind1.s b/ld/testsuite/ld-elf/mbind1.s
new file mode 100644
index 0000000..414b9fe
--- /dev/null
+++ b/ld/testsuite/ld-elf/mbind1.s
@@ -0,0 +1,43 @@
+	.text
+	.global start	/* Used by SH targets.  */
+start:
+	.global _start
+_start:
+	.global __start
+__start:
+	.global main	/* Used by HPPA targets.  */
+main:
+	.dc.a 0
+	.section .mbind.data,"adw",%progbits
+	.byte 1
+
+	.section .mbind.data,"adw",%progbits,0x3
+	.byte 2
+
+	.section .mbind.text,"adx",%progbits
+	.byte 3
+
+	.section .mbind.text,"adx",%progbits,0x3
+	.byte 4
+
+	.section .mbind.bss,"adw",%nobits
+	.zero 5
+
+	.section .mbind.bss,"adw",%nobits,0x3
+	.zero 6
+
+	.section .mbind.rodata,"adG",%progbits,.foo_group,comdat,0x2
+	.byte 7
+
+	.section .mbind.data,"adGw",%progbits,.foo_group,comdat
+	.byte 8
+
+	.section .mbind.data,"adGw",%progbits,.foo_group,comdat,0x3
+	.byte 9
+
+	# Check that .pushsection works as well.
+	.pushsection .mbind.text,"adGx",%progbits,.foo_group,comdat,0x3
+	.byte 10
+
+	.popsection
+	.byte 11
diff --git a/ld/testsuite/ld-elf/mbind1a.d b/ld/testsuite/ld-elf/mbind1a.d
new file mode 100644
index 0000000..aabf781
--- /dev/null
+++ b/ld/testsuite/ld-elf/mbind1a.d
@@ -0,0 +1,44 @@
+#source: mbind1.s
+#ld: -z common-page-size=0x1000 -z max-page-size=0x200000
+#readelf: -S -l --wide
+#target: *-*-linux* *-*-gnu*
+
+#...
+  \[[ 0-9]+\] \.mbind\.text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXD  0   0 4096
+  \[[ 0-9]+\] \.mbind\.text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXD  0   3 4096
+  \[[ 0-9]+\] \.mbind\.rodata[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AD  0   2 4096
+#...
+  \[[ 0-9]+\] \.mbind\.data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   0 4096
+  \[[ 0-9]+\] \.mbind\.data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   3 4096
+#...
+  \[[ 0-9]+\] \.mbind\.bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   0 4096
+  \[[ 0-9]+\] \.mbind\.bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   3 4096
+#...
+Program Headers:
+  Type.*
+#...
+  LOAD[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x200000
+  LOAD[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x200000
+#...
+  GNU_MBIND\+0[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x1000
+  GNU_MBIND\+0x3[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x1000
+  GNU_MBIND\+0x2[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R   0x1000
+  GNU_MBIND\+0[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+  GNU_MBIND\+0x3[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+  GNU_MBIND\+0[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+  GNU_MBIND\+0x3[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+#...
+ Section to Segment mapping:
+  Segment Sections...
+#...
+   [0-9]+     .*.text .mbind.text .mbind.text .mbind.rodata .*
+   [0-9]+     .*.mbind.data .mbind.data.* .mbind.bss .mbind.bss .*
+#...
+   [0-9]+     .mbind.text +
+   [0-9]+     .mbind.text +
+   [0-9]+     .mbind.rodata +
+   [0-9]+     .mbind.data +
+   [0-9]+     .mbind.data +
+   [0-9]+     .mbind.bss +
+   [0-9]+     .mbind.bss +
+#pass
diff --git a/ld/testsuite/ld-elf/mbind1b.d b/ld/testsuite/ld-elf/mbind1b.d
new file mode 100644
index 0000000..f161108
--- /dev/null
+++ b/ld/testsuite/ld-elf/mbind1b.d
@@ -0,0 +1,44 @@
+#source: mbind1.s
+#ld: -shared -z common-page-size=0x1000 -z max-page-size=0x200000
+#readelf: -S -l --wide
+#target: *-*-linux* *-*-gnu*
+
+#...
+  \[[ 0-9]+\] \.mbind\.text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXD  0   0 4096
+  \[[ 0-9]+\] \.mbind\.text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXD  0   3 4096
+  \[[ 0-9]+\] \.mbind\.rodata[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AD  0   2 4096
+#...
+  \[[ 0-9]+\] \.mbind\.data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   0 4096
+  \[[ 0-9]+\] \.mbind\.data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   3 4096
+#...
+  \[[ 0-9]+\] \.mbind\.bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   0 4096
+  \[[ 0-9]+\] \.mbind\.bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   3 4096
+#...
+Program Headers:
+  Type.*
+#...
+  LOAD[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x200000
+  LOAD[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x200000
+#...
+  GNU_MBIND\+0[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x1000
+  GNU_MBIND\+0x3[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x1000
+  GNU_MBIND\+0x2[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R   0x1000
+  GNU_MBIND\+0[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+  GNU_MBIND\+0x3[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+  GNU_MBIND\+0[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+  GNU_MBIND\+0x3[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+#...
+ Section to Segment mapping:
+  Segment Sections...
+#...
+   [0-9]+     .*.text .mbind.text .mbind.text .mbind.rodata .*
+   [0-9]+     .*.mbind.data .mbind.data.* .mbind.bss .mbind.bss .*
+#...
+   [0-9]+     .mbind.text +
+   [0-9]+     .mbind.text +
+   [0-9]+     .mbind.rodata +
+   [0-9]+     .mbind.data +
+   [0-9]+     .mbind.data +
+   [0-9]+     .mbind.bss +
+   [0-9]+     .mbind.bss +
+#pass
diff --git a/ld/testsuite/ld-elf/mbind1c.d b/ld/testsuite/ld-elf/mbind1c.d
new file mode 100644
index 0000000..1348d0c
--- /dev/null
+++ b/ld/testsuite/ld-elf/mbind1c.d
@@ -0,0 +1,44 @@
+#source: mbind1.s
+#ld: -pie -z common-page-size=0x1000 -z max-page-size=0x200000
+#readelf: -S -l --wide
+#target: *-*-linux* *-*-gnu*
+
+#...
+  \[[ 0-9]+\] \.mbind\.text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXD  0   0 4096
+  \[[ 0-9]+\] \.mbind\.text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXD  0   3 4096
+  \[[ 0-9]+\] \.mbind\.rodata[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AD  0   2 4096
+#...
+  \[[ 0-9]+\] \.mbind\.data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   0 4096
+  \[[ 0-9]+\] \.mbind\.data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   3 4096
+#...
+  \[[ 0-9]+\] \.mbind\.bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   0 4096
+  \[[ 0-9]+\] \.mbind\.bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAD  0   3 4096
+#...
+Program Headers:
+  Type.*
+#...
+  LOAD[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x200000
+  LOAD[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x200000
+#...
+  GNU_MBIND\+0[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x1000
+  GNU_MBIND\+0x3[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x1000
+  GNU_MBIND\+0x2[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R   0x1000
+  GNU_MBIND\+0[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+  GNU_MBIND\+0x3[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+  GNU_MBIND\+0[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+  GNU_MBIND\+0x3[ \t]+0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW  0x1000
+#...
+ Section to Segment mapping:
+  Segment Sections...
+#...
+   [0-9]+     .*.text .mbind.text .mbind.text .mbind.rodata .*
+   [0-9]+     .*.mbind.data .mbind.data.* .mbind.bss .mbind.bss .*
+#...
+   [0-9]+     .mbind.text +
+   [0-9]+     .mbind.text +
+   [0-9]+     .mbind.rodata +
+   [0-9]+     .mbind.data +
+   [0-9]+     .mbind.data +
+   [0-9]+     .mbind.bss +
+   [0-9]+     .mbind.bss +
+#pass
diff --git a/ld/testsuite/ld-elf/mbind2a.s b/ld/testsuite/ld-elf/mbind2a.s
new file mode 100644
index 0000000..2da9792
--- /dev/null
+++ b/ld/testsuite/ld-elf/mbind2a.s
@@ -0,0 +1,15 @@
+/* Place bss_in_mbind0 in .mbind.bss section with sh_info == 0.  */
+	.globl bss_in_mbind0
+	.section .mbind.bss,"adw",@nobits,0
+	.type bss_in_mbind0, @object
+	.size bss_in_mbind0, 1
+bss_in_mbind0:
+	.zero 1
+
+/* Place data_in_mbind3 in .mbind.data section with sh_info == 3.  */
+	.globl data_in_mbind3
+	.section .mbind.data,"adw",@progbits,0x3
+	.type data_in_mbind3, @object
+	.size data_in_mbind3, 1
+data_in_mbind3:
+	.byte 0
diff --git a/ld/testsuite/ld-elf/mbind2b.c b/ld/testsuite/ld-elf/mbind2b.c
new file mode 100644
index 0000000..10922a1
--- /dev/null
+++ b/ld/testsuite/ld-elf/mbind2b.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <bfd_stdint.h>
+
+extern char bss_in_mbind0;
+extern char data_in_mbind3;
+
+int
+main (void)
+{
+  if (((intptr_t) &bss_in_mbind0 & (0x4000 - 1)) != 0)
+    abort ();
+  if (((intptr_t) &data_in_mbind3 & (0x4000 - 1)) != 0)
+    abort ();
+  printf ("PASS\n");
+  return 0;
+}
-- 
2.9.3

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Support SHF_GNU_MBIND and PT_GNU_MBIND_XXX
  2017-03-15 22:46 [PATCH] Support SHF_GNU_MBIND and PT_GNU_MBIND_XXX H.J. Lu
@ 2017-03-17  3:38 ` Alan Modra
  2017-03-17 15:58   ` H.J. Lu
  0 siblings, 1 reply; 5+ messages in thread
From: Alan Modra @ 2017-03-17  3:38 UTC (permalink / raw)
  To: H.J. Lu; +Cc: binutils

On Wed, Mar 15, 2017 at 03:46:17PM -0700, H.J. Lu wrote:
> Any comments?

Doesn't pass my sniff test.

You say that management of special memory regions doesn't belong in
the kernel or glibc, but will be handled by a vendor supplied
library.  In that case, why must ld.so run your magic
__gnu_mbind_setup function?  If ld.so doesn't need to run
__gnu_mbind_setup then there's no need to pass information to ld.so
via special segment types and flags.

Just have the application call __gnu_mbind_setup.  The function
can take the address range(s) requested as a parameter rather than
putting them into the executable headers.  It shouldn't be difficult
for the linker to arrange such a call on application startup.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Support SHF_GNU_MBIND and PT_GNU_MBIND_XXX
  2017-03-17  3:38 ` Alan Modra
@ 2017-03-17 15:58   ` H.J. Lu
  2017-03-19 11:39     ` Alan Modra
  0 siblings, 1 reply; 5+ messages in thread
From: H.J. Lu @ 2017-03-17 15:58 UTC (permalink / raw)
  To: Alan Modra; +Cc: Binutils

On Thu, Mar 16, 2017 at 8:38 PM, Alan Modra <amodra@gmail.com> wrote:
> On Wed, Mar 15, 2017 at 03:46:17PM -0700, H.J. Lu wrote:
>> Any comments?
>
> Doesn't pass my sniff test.
>
> You say that management of special memory regions doesn't belong in
> the kernel or glibc, but will be handled by a vendor supplied
> library.  In that case, why must ld.so run your magic
> __gnu_mbind_setup function?  If ld.so doesn't need to run

 __gnu_mbind_setup needs to called with memory type, address and
length in executable, DSOs and dlopened DSOs before constructors
are called.

> __gnu_mbind_setup then there's no need to pass information to ld.so
> via special segment types and flags.
>
> Just have the application call __gnu_mbind_setup.  The function
> can take the address range(s) requested as a parameter rather than
> putting them into the executable headers.  It shouldn't be difficult
> for the linker to arrange such a call on application startup.
>

The goal is to place data in special memory sections via attribute.
To place an uninitialized variable, foo, in a mbind bss section with
memory type 1:

int foo __attribute__ ((mbind(0x1)));

To place a variable, foo, in a mbind data section with memory type 2:

int foo __attribute__ ((mbind(0x2))) = 1;

To place a read-only variable, foo, in a mbind rodata section with
memory type 3:

const int foo __attribute__ ((mbind(0x3))) = 1;

How can linker arrange calling __gnu_mbind_setup in executable,
DSOs and dlopened DSOs before constructors are called?


-- 
H.J.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Support SHF_GNU_MBIND and PT_GNU_MBIND_XXX
  2017-03-17 15:58   ` H.J. Lu
@ 2017-03-19 11:39     ` Alan Modra
  2017-03-20 16:35       ` H.J. Lu
  0 siblings, 1 reply; 5+ messages in thread
From: Alan Modra @ 2017-03-19 11:39 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Binutils

On Fri, Mar 17, 2017 at 08:58:02AM -0700, H.J. Lu wrote:
> On Thu, Mar 16, 2017 at 8:38 PM, Alan Modra <amodra@gmail.com> wrote:
> > On Wed, Mar 15, 2017 at 03:46:17PM -0700, H.J. Lu wrote:
> >> Any comments?
> >
> > Doesn't pass my sniff test.
> >
> > You say that management of special memory regions doesn't belong in
> > the kernel or glibc, but will be handled by a vendor supplied
> > library.  In that case, why must ld.so run your magic
> > __gnu_mbind_setup function?  If ld.so doesn't need to run
> 
>  __gnu_mbind_setup needs to called with memory type, address and
> length in executable, DSOs and dlopened DSOs before constructors
> are called.

I presume if it is supposed to work with dlopen then you're saying
__gnu_mbind_setup will be called for the executable and each DSO.
ie. We're not talking about a case where __gnu_mbind_setup is called
once after the executable and all DSOs have been loaded.  If that is
the case, then yes, it is probably most convenient to have ld.so
involved.

> > __gnu_mbind_setup then there's no need to pass information to ld.so
> > via special segment types and flags.
> >
> > Just have the application call __gnu_mbind_setup.  The function
> > can take the address range(s) requested as a parameter rather than
> > putting them into the executable headers.  It shouldn't be difficult
> > for the linker to arrange such a call on application startup.
> >
> 
> The goal is to place data in special memory sections via attribute.
> To place an uninitialized variable, foo, in a mbind bss section with
> memory type 1:
> 
> int foo __attribute__ ((mbind(0x1)));
> 
> To place a variable, foo, in a mbind data section with memory type 2:
> 
> int foo __attribute__ ((mbind(0x2))) = 1;
> 
> To place a read-only variable, foo, in a mbind rodata section with
> memory type 3:
> 
> const int foo __attribute__ ((mbind(0x3))) = 1;

I think the relocatable object support is fine.  It's just the new
program header I'm questioning, and only because it seemed to me that
ld.so didn't need to be involved.  If ld.so isn't involved then you
can support the feature on older glibc.

> How can linker arrange calling __gnu_mbind_setup in executable,
> DSOs and dlopened DSOs before constructors are called?

By making that call the very first constructor.  I'm not sure whether
you want to run before DT_PREINIT_ARRAY constructors (or should!).  It
would be easier if not, because then you'd be able to hook into crti.o
_init and pass parameters more easily, either using the same trick of
a weak __gnu_mbind_setup call or have ld edit the _init code.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Support SHF_GNU_MBIND and PT_GNU_MBIND_XXX
  2017-03-19 11:39     ` Alan Modra
@ 2017-03-20 16:35       ` H.J. Lu
  0 siblings, 0 replies; 5+ messages in thread
From: H.J. Lu @ 2017-03-20 16:35 UTC (permalink / raw)
  To: Alan Modra; +Cc: Binutils

On Sun, Mar 19, 2017 at 4:38 AM, Alan Modra <amodra@gmail.com> wrote:
> On Fri, Mar 17, 2017 at 08:58:02AM -0700, H.J. Lu wrote:
>> On Thu, Mar 16, 2017 at 8:38 PM, Alan Modra <amodra@gmail.com> wrote:
>> > On Wed, Mar 15, 2017 at 03:46:17PM -0700, H.J. Lu wrote:
>> >> Any comments?
>> >
>> > Doesn't pass my sniff test.
>> >
>> > You say that management of special memory regions doesn't belong in
>> > the kernel or glibc, but will be handled by a vendor supplied
>> > library.  In that case, why must ld.so run your magic
>> > __gnu_mbind_setup function?  If ld.so doesn't need to run
>>
>>  __gnu_mbind_setup needs to called with memory type, address and
>> length in executable, DSOs and dlopened DSOs before constructors
>> are called.
>
> I presume if it is supposed to work with dlopen then you're saying
> __gnu_mbind_setup will be called for the executable and each DSO.
> ie. We're not talking about a case where __gnu_mbind_setup is called
> once after the executable and all DSOs have been loaded.  If that is
> the case, then yes, it is probably most convenient to have ld.so
> involved.

__gnu_mbind_setup is called once on each MBIND segment after
the executable and all DSOs have been loaded and relocated.

>> > __gnu_mbind_setup then there's no need to pass information to ld.so
>> > via special segment types and flags.
>> >
>> > Just have the application call __gnu_mbind_setup.  The function
>> > can take the address range(s) requested as a parameter rather than
>> > putting them into the executable headers.  It shouldn't be difficult
>> > for the linker to arrange such a call on application startup.
>> >
>>
>> The goal is to place data in special memory sections via attribute.
>> To place an uninitialized variable, foo, in a mbind bss section with
>> memory type 1:
>>
>> int foo __attribute__ ((mbind(0x1)));
>>
>> To place a variable, foo, in a mbind data section with memory type 2:
>>
>> int foo __attribute__ ((mbind(0x2))) = 1;
>>
>> To place a read-only variable, foo, in a mbind rodata section with
>> memory type 3:
>>
>> const int foo __attribute__ ((mbind(0x3))) = 1;
>
> I think the relocatable object support is fine.  It's just the new
> program header I'm questioning, and only because it seemed to me that
> ld.so didn't need to be involved.  If ld.so isn't involved then you
> can support the feature on older glibc.

ld.so is used to iterate all MBIND regions to call __gnu_mbind_setup
with their addresses and sizes.  Ii is hard to do without ld.so.

>> How can linker arrange calling __gnu_mbind_setup in executable,
>> DSOs and dlopened DSOs before constructors are called?
>
> By making that call the very first constructor.  I'm not sure whether
> you want to run before DT_PREINIT_ARRAY constructors (or should!).  It

A sperare MBIND initialization function needs to be called to initalize
data which is needed by __gnu_mbind_setup.  I am planning to
place it at the beginning of .preinit_array section.

> would be easier if not, because then you'd be able to hook into crti.o
> _init and pass parameters more easily, either using the same trick of
> a weak __gnu_mbind_setup call or have ld edit the _init code.
>


-- 
H.J.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-03-20 16:35 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-15 22:46 [PATCH] Support SHF_GNU_MBIND and PT_GNU_MBIND_XXX H.J. Lu
2017-03-17  3:38 ` Alan Modra
2017-03-17 15:58   ` H.J. Lu
2017-03-19 11:39     ` Alan Modra
2017-03-20 16:35       ` H.J. Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).