This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC PATCH] pad out code segment for NaCl targets


For NaCl targets, I want to get the code segment to be padded out to the
ABI page size in the file (with appropriate fill patterns per CPU).  This
is a (new) ABI requirement so that the system can map in all the whole
pages of the code segment without seeing any part of the file in the memory
image that does not contain valid machine instructions.

I've figured out a way to make this happen, but I'm not very happy with it.
I hope someone can recommend a different approach that will serve me better.

In the linker script, I can do this:

  .NaCl.pad.code :
  {
    . = ALIGN(CONSTANT (MAXPAGESIZE));
  }

But that results in the output section being SHT_NOBITS and SHF_WRITE,
generating its own separate segment that is writable and not executable.
I can instead make it this:

  .NaCl.pad.code :
  {
    KEEP (*(.NaCl.pad.code))
    . = ALIGN(CONSTANT (MAXPAGESIZE));
  }

and that works if there is some input section called .NaCl.pad.code that
has the right flags (even an empty section).  So the best I've come up with
is to do that, and have my linker emulation code synthesize a fake input
file containing this fake input section.  That patch below implements this.

This is less than ideal in a few ways:

* If the input contained any real sections called .NaCl.pad.code, then they
  would get placed here and louse things up.  In practice, the placement is
  probably where they'd be anyway if they are read-only executable
  sections, but if they have different flags things will go all bad.

* The output contains this stupid section called .NaCl.pad.code, which I'd
  prefer not to see at all.  It is mildly unsightly that it gets generated
  and one has to see it using readelf/objdump/etc.  The real practical
  hassle here is that numerous ld testsuite cases start failing to match
  their expected disassembly or symbol table output.  I would really prefer
  not to have to disable or tweak yet more test cases for a NaCl variant
  when the NaCl difference has nothing to do with the purpose of the test.

* It's just a giant kludge.  Given, this is BFD, so... kludges, BFD.
  But it sure would be nice to get this done some other way.

* There is probably some other downside I'm overlooking at the moment.


So, can anyone suggest an alternate approach that would avoid those problems?


Thanks,
Roland


bfd/
2013-08-08  Roland McGrath  <mcgrathr@google.com>

	* elf32-arm.c (elf32_arm_merge_private_bfd_data): Punt early if
	IBFD has BFD_LINKER_CREATED.

ld/
2013-08-08  Roland McGrath  <mcgrathr@google.com>

	* scripttempl/elf.sc: Use ${AFTER_CODE} at the end of the
	code-segment sections, after etext.
	* emultempl/naclelf.em: New file.
	* emulparams/elf_nacl.sh (NACL_EXTRA_EM_FILE): Set to ${EXTRA_EM_FILE}.
	(EXTRA_EM_FILE): Set to naclelf.
	(AFTER_CODE): Set it.
	* emulparams/elf_i386_nacl.sh (NOP): Set it to 0x90.
	* emulparams/elf_x86_64_nacl.sh: Likewise.
	* emulparams/elf32_x86_64_nacl.sh: Likewise.
	* Makefile.am (earmelf_nacl.c, earmelfb_nacl.c): Depend on
	$(srcdir)/emultempl/naclelf.em too.
	(eelf_i386_nacl.c, eelf32_x86_64_nacl.c, eelf_x86_64_nacl.c): Likewise.
	* Makefile.in: Regenerate.

--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -15955,6 +15955,9 @@ elf32_arm_merge_private_bfd_data (bfd * ibfd,
bfd * obfd)
   bfd_boolean flags_compatible = TRUE;
   asection *sec;

+  if (ibfd->flags & BFD_LINKER_CREATED)
+    return TRUE;
+
   /* Check if we have the same endianness.  */
   if (! _bfd_generic_verify_endian_match (ibfd, obfd))
     return FALSE;
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -1,6 +1,6 @@
 ## Process this file with automake to generate Makefile.in
 #
-#   Copyright 2012 Free Software Foundation
+#   Copyright 2012, 2013 Free Software Foundation
 #
 # This file is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -744,7 +744,7 @@ earmelf_linux_eabi.c:
$(srcdir)/emulparams/armelf_linux_eabi.sh \
 earmelf_nacl.c: $(srcdir)/emulparams/armelf_nacl.sh \
   $(srcdir)/emulparams/armelf_linux_eabi.sh \
   $(srcdir)/emulparams/armelf_linux.sh \
-  $(srcdir)/emulparams/elf_nacl.sh \
+  $(srcdir)/emulparams/elf_nacl.sh $(srcdir)/emultempl/naclelf.em \
   $(ELF_DEPS) $(srcdir)/emultempl/armelf.em \
   $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} armelf_nacl "$(tdir_armelf_nacl)"
@@ -778,7 +778,7 @@ earmelfb_nacl.c: $(srcdir)/emulparams/armelfb_nacl.sh \
   $(srcdir)/emulparams/armelf_nacl.sh \
   $(srcdir)/emulparams/armelf_linux_eabi.sh \
   $(srcdir)/emulparams/armelf_linux.sh \
-  $(srcdir)/emulparams/elf_nacl.sh \
+  $(srcdir)/emulparams/elf_nacl.sh $(srcdir)/emultempl/naclelf.em \
   $(ELF_DEPS) $(srcdir)/emultempl/armelf.em \
   $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} armelfb_nacl "$(tdir_armelfb_nacl)"
@@ -1281,7 +1281,7 @@ eelf_i386_ldso.c: $(srcdir)/emulparams/elf_i386_ldso.sh \
 	${GENSCRIPTS} elf_i386_ldso "$(tdir_elf_i386_ldso)"
 eelf_i386_nacl.c: $(srcdir)/emulparams/elf_i386_nacl.sh \
   $(srcdir)/emulparams/elf_i386.sh \
-  $(srcdir)/emulparams/elf_nacl.sh \
+  $(srcdir)/emulparams/elf_nacl.sh $(srcdir)/emultempl/naclelf.em \
   $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} elf_i386_nacl "$(tdir_elf_i386_nacl)"
 eelf_i386_sol2.c: $(srcdir)/emulparams/elf_i386_sol2.sh \
@@ -2000,7 +2000,7 @@ eelf32_x86_64.c: $(srcdir)/emulparams/elf32_x86_64.sh \
 	${GENSCRIPTS} elf32_x86_64 "$(tdir_elf32_x86_64)"
 eelf32_x86_64_nacl.c: $(srcdir)/emulparams/elf32_x86_64_nacl.sh \
   $(srcdir)/emulparams/elf32_x86_64.sh \
-  $(srcdir)/emulparams/elf_nacl.sh \
+  $(srcdir)/emulparams/elf_nacl.sh $(srcdir)/emultempl/naclelf.em \
   $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} elf32_x86_64_nacl "$(tdir_elf32_x86_64_nacl)"
 eelf64_aix.c: $(srcdir)/emulparams/elf64_aix.sh \
@@ -2131,7 +2131,7 @@ eelf_x86_64_fbsd.c:
$(srcdir)/emulparams/elf_x86_64_fbsd.sh \
 	${GENSCRIPTS} elf_x86_64_fbsd "$(tdir_elf_x86_64_fbsd)"
 eelf_x86_64_nacl.c: $(srcdir)/emulparams/elf_x86_64_nacl.sh \
   $(srcdir)/emulparams/elf_x86_64.sh \
-  $(srcdir)/emulparams/elf_nacl.sh \
+  $(srcdir)/emulparams/elf_nacl.sh $(srcdir)/emultempl/naclelf.em \
   $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} elf_x86_64_nacl "$(tdir_elf_x86_64_nacl)"
 eelf_x86_64_sol2.c: $(srcdir)/emulparams/elf_x86_64_sol2.sh \
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -16,7 +16,7 @@
 @SET_MAKE@

 #
-#   Copyright 2012 Free Software Foundation
+#   Copyright 2012, 2013 Free Software Foundation
 #
 # This file is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -2226,7 +2226,7 @@ earmelf_linux_eabi.c:
$(srcdir)/emulparams/armelf_linux_eabi.sh \
 earmelf_nacl.c: $(srcdir)/emulparams/armelf_nacl.sh \
   $(srcdir)/emulparams/armelf_linux_eabi.sh \
   $(srcdir)/emulparams/armelf_linux.sh \
-  $(srcdir)/emulparams/elf_nacl.sh \
+  $(srcdir)/emulparams/elf_nacl.sh $(srcdir)/emultempl/naclelf.em \
   $(ELF_DEPS) $(srcdir)/emultempl/armelf.em \
   $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} armelf_nacl "$(tdir_armelf_nacl)"
@@ -2260,7 +2260,7 @@ earmelfb_nacl.c: $(srcdir)/emulparams/armelfb_nacl.sh \
   $(srcdir)/emulparams/armelf_nacl.sh \
   $(srcdir)/emulparams/armelf_linux_eabi.sh \
   $(srcdir)/emulparams/armelf_linux.sh \
-  $(srcdir)/emulparams/elf_nacl.sh \
+  $(srcdir)/emulparams/elf_nacl.sh $(srcdir)/emultempl/naclelf.em \
   $(ELF_DEPS) $(srcdir)/emultempl/armelf.em \
   $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} armelfb_nacl "$(tdir_armelfb_nacl)"
@@ -2763,7 +2763,7 @@ eelf_i386_ldso.c: $(srcdir)/emulparams/elf_i386_ldso.sh \
 	${GENSCRIPTS} elf_i386_ldso "$(tdir_elf_i386_ldso)"
 eelf_i386_nacl.c: $(srcdir)/emulparams/elf_i386_nacl.sh \
   $(srcdir)/emulparams/elf_i386.sh \
-  $(srcdir)/emulparams/elf_nacl.sh \
+  $(srcdir)/emulparams/elf_nacl.sh $(srcdir)/emultempl/naclelf.em \
   $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} elf_i386_nacl "$(tdir_elf_i386_nacl)"
 eelf_i386_sol2.c: $(srcdir)/emulparams/elf_i386_sol2.sh \
@@ -3482,7 +3482,7 @@ eelf32_x86_64.c: $(srcdir)/emulparams/elf32_x86_64.sh \
 	${GENSCRIPTS} elf32_x86_64 "$(tdir_elf32_x86_64)"
 eelf32_x86_64_nacl.c: $(srcdir)/emulparams/elf32_x86_64_nacl.sh \
   $(srcdir)/emulparams/elf32_x86_64.sh \
-  $(srcdir)/emulparams/elf_nacl.sh \
+  $(srcdir)/emulparams/elf_nacl.sh $(srcdir)/emultempl/naclelf.em \
   $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} elf32_x86_64_nacl "$(tdir_elf32_x86_64_nacl)"
 eelf64_aix.c: $(srcdir)/emulparams/elf64_aix.sh \
@@ -3613,7 +3613,7 @@ eelf_x86_64_fbsd.c:
$(srcdir)/emulparams/elf_x86_64_fbsd.sh \
 	${GENSCRIPTS} elf_x86_64_fbsd "$(tdir_elf_x86_64_fbsd)"
 eelf_x86_64_nacl.c: $(srcdir)/emulparams/elf_x86_64_nacl.sh \
   $(srcdir)/emulparams/elf_x86_64.sh \
-  $(srcdir)/emulparams/elf_nacl.sh \
+  $(srcdir)/emulparams/elf_nacl.sh $(srcdir)/emultempl/naclelf.em \
   $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} elf_x86_64_nacl "$(tdir_elf_x86_64_nacl)"
 eelf_x86_64_sol2.c: $(srcdir)/emulparams/elf_x86_64_sol2.sh \
--- a/ld/emulparams/elf32_x86_64_nacl.sh
+++ b/ld/emulparams/elf32_x86_64_nacl.sh
@@ -1,3 +1,8 @@
 . ${srcdir}/emulparams/elf32_x86_64.sh
+# By default, BFD will use varying sizes of NOPs to fill.  Since it doesn't
+# know about the instruction bundle constraint, that can produce individual
+# long NOP instructions that would straddle a boundary, violating the NaCl
+# ABI constraints.  Using a single-byte NOP avoids that possibility.
+NOP=0x90
 . ${srcdir}/emulparams/elf_nacl.sh
 OUTPUT_FORMAT="elf32-x86-64-nacl"
--- a/ld/emulparams/elf_i386_nacl.sh
+++ b/ld/emulparams/elf_i386_nacl.sh
@@ -1,3 +1,8 @@
 . ${srcdir}/emulparams/elf_i386.sh
+# By default, BFD will use varying sizes of NOPs to fill.  Since it doesn't
+# know about the instruction bundle constraint, that can produce individual
+# long NOP instructions that would straddle a boundary, violating the NaCl
+# ABI constraints.  Using a single-byte NOP avoids that possibility.
+NOP=0x90
 . ${srcdir}/emulparams/elf_nacl.sh
 OUTPUT_FORMAT="elf32-i386-nacl"
--- a/ld/emulparams/elf_nacl.sh
+++ b/ld/emulparams/elf_nacl.sh
@@ -1,5 +1,6 @@
 ENABLE_INITFINI_ARRAY=yes
 SEPARATE_CODE=yes
+PAD_CODE_SEGMENT=yes
 TEXT_START_ADDR=0x20000
 NACL_RODATA_DISTANCE=0x10000000

@@ -12,3 +13,16 @@ nacl_rodata_addr()

 RODATA_ADDR=`nacl_rodata_addr "${TEXT_START_ADDR}"`
 SHLIB_RODATA_ADDR=`nacl_rodata_addr 0`
+
+NACL_EXTRA_EM_FILE=${EXTRA_EM_FILE}
+EXTRA_EM_FILE=naclelf
+
+NACL_PAD_CODE="
+  .NaCl.pad.code :
+  {
+    KEEP (*(.NaCl.pad.code))
+    . = ALIGN(${MAXPAGESIZE});
+  } ${NOP:+=$NOP}
+"
+
+AFTER_CODE="${RELOCATING+${NACL_PAD_CODE}}"
--- a/ld/emulparams/elf_x86_64_nacl.sh
+++ b/ld/emulparams/elf_x86_64_nacl.sh
@@ -1,3 +1,8 @@
 . ${srcdir}/emulparams/elf_x86_64.sh
+# By default, BFD will use varying sizes of NOPs to fill.  Since it doesn't
+# know about the instruction bundle constraint, that can produce individual
+# long NOP instructions that would straddle a boundary, violating the NaCl
+# ABI constraints.  Using a single-byte NOP avoids that possibility.
+NOP=0x90
 . ${srcdir}/emulparams/elf_nacl.sh
 OUTPUT_FORMAT="elf64-x86-64-nacl"
--- /dev/null
+++ b/ld/emultempl/naclelf.em
@@ -0,0 +1,88 @@
+# This shell script emits a C file. -*- C -*-
+#   Copyright 2013 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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.
+#
+
+# This file is sourced from elf32.em, and defines extra NaCl-specific routines.
+
+# Import any machine-specific stuff.
+if test -n "$NACL_EXTRA_EM_FILE" ; then
+  source_em ${srcdir}/emultempl/${NACL_EXTRA_EM_FILE}.em
+fi
+
+fragment <<EOF
+/* NaCl objects should have a code segment that is padded out to the ABI
+   page size, so that an entire code segment of whole pages can be
+   mapped in and contain nothing but valid machine instructions.
+   emulparams/elf_nacl.sh inserts .NaCl.pad.code into the linker
+   script, but this only works right if there is a .NaCl.pad.code
+   input section somewhere in the link (an empty section with the right
+   flags is all it takes).  So we synthesize a fake input file just to
+   hold the fake input section with this special name.  */
+static void
+pad_code_segment (void)
+{
+  lang_input_statement_type *pad_file;
+  asection *pad_sec;
+
+  pad_file = lang_add_input_file ("pad code segment",
+				  lang_input_file_is_fake_enum,
+				  NULL);
+  pad_file->the_bfd = bfd_create ("pad code segment", link_info.output_bfd);
+  if (pad_file->the_bfd == NULL
+      || ! bfd_set_arch_mach (pad_file->the_bfd,
+			      bfd_get_arch (link_info.output_bfd),
+			      bfd_get_mach (link_info.output_bfd)))
+    {
+      einfo ("%X%P: cannot create BFD: %E\n");
+      return;
+    }
+
+  pad_file->the_bfd->flags |= BFD_LINKER_CREATED;
+  ldlang_add_file (pad_file);
+
+  pad_sec = bfd_make_section_anyway_with_flags (pad_file->the_bfd,
+						".NaCl.pad.code",
+						SEC_HAS_CONTENTS
+						| SEC_ALLOC
+						| SEC_LOAD
+						| SEC_READONLY
+						| SEC_CODE
+						| SEC_IN_MEMORY
+						| SEC_LINKER_CREATED
+						| SEC_KEEP);
+  if (pad_sec == NULL)
+    {
+      einfo ("%X%P: cannot create .NaCl.pad.code section: %E\n");
+      return;
+    }
+}
+
+static void
+nacl_elf_after_open (void)
+{
+  if (!link_info.relocatable)
+    pad_code_segment ();
+  ${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open} ();
+}
+EOF
+
+# We have our own after_open function, but it calls the standard one, so
+# give it a different name.
+LDEMUL_AFTER_OPEN=nacl_elf_after_open
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -58,6 +58,7 @@
 #	SEPARATE_CODE - if set, .text and similar sections containing
 #		actual machine instructions must be in wholly disjoint
 #		pages from any other data, including headers
+#	AFTER_CODE - if set, fragment to appear after etext
 #	SEPARATE_GOTPLT - if set, .got.plt should be separate output section,
 #		so that .got can be in the RELRO area.  It should be set to
 #		the number of bytes in the beginning of .got.plt which can be
@@ -488,6 +489,7 @@ cat <<EOF
   ${RELOCATING+PROVIDE (__${ETEXT_NAME} = .);}
   ${RELOCATING+PROVIDE (_${ETEXT_NAME} = .);}
   ${RELOCATING+PROVIDE (${ETEXT_NAME} = .);}
+${AFTER_CODE}
 EOF

 if test -n "${SEPARATE_CODE}"; then


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]