tech-toolchain archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Workaround objcopy bugs with writable .eh_frame



Hello,
the recently added support for thread_local exposed a latent bug in
objcopy as used by crunchgen. If the .eh_frame section is writable,
objcopy will create a bogus PT_TLS segment as it forgets the .tbss and
.tdata sections in the mapping. As I haven't found an easy way to fix
that, I've settled for fixing another bug as workaround. GCC 5.3 decides
that a zero-initialized variable (or a zero-sized variable for that
matter) is meant for BSS, even if the variable has an explicit output
section assigned. Since data in BSS can't be const, GCC doesn't tag the
section as read-only either.

All platforms using crtbegin.c except MIPS have a writable .eh_frame
section as result and this triggers a different layout, which results in
the above mentioned objcopy bug.

MIPS uses crtbegin.c, but is even more tricky. For historic
brain-dead reasons, MIPS doesn't allow position-relative relocations to
symbols in different sections. This makes it impossible to write
.eh_frame entries directly without creating relocations. The move to
.cfi instructions was supposed to fix this, but due to ordering issues
in the GNU ld processing, it didn't work. The solution I came up with
works in two parts: first, all references in the .eh_frame output are
stored as absolute pointers. The later fixup handling will make them
relative where necessary. The second part is to ignore relocations in
the .eh_frame section, even if it is read-only and the output must be
PIC. As the relocations do not contain symbols, they are known to be
build-time resolvable by the eh_frame fixup. Just skipping them is
enough. This allows dropping the MIPS hack in crtbegin.c in combination
with the GCC fix for the remaining platforms.

After fixing this bug on MIPS and solving an unrelated spec bug I
stumbled over ("why do static binaries have no .eh_frame_hdr???"), it
still didn't work as expectec for evbmips64. Turns out that GCC decided
to not not use .cfi instructions, because objcopy's DWARF parser
mishandled the test case. Luckily, changing the same configure test to
use readelf's DWARF parser works fine. Don't ask me why there are two
different DWARF parsers...

All in all, the result should work on all platforms, but please tell me,
if there any remaining issues.

Joerg
Index: external/gpl3/binutils/dist/bfd/elfxx-mips.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/external/gpl3/binutils/dist/bfd/elfxx-mips.c,v
retrieving revision 1.10
diff -u -p -r1.10 elfxx-mips.c
--- external/gpl3/binutils/dist/bfd/elfxx-mips.c	26 Oct 2016 18:42:52 -0000	1.10
+++ external/gpl3/binutils/dist/bfd/elfxx-mips.c	16 Jul 2017 00:08:40 -0000
@@ -8596,12 +8596,18 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
 		  /* In the N32 and 64-bit ABIs there may be multiple
 		     consecutive relocations for the same offset.  If we have
 		     a R_MIPS_GPREL32 followed by a R_MIPS_64 then that
-		     relocation is complete and needs no futher adjustment.  */
+		     relocation is complete and needs no futher adjustment.
+		     
+		     Silently ignore absolute relocations in the .eh_frame
+		     section, they will be dropped latter.
+		   */
 		  if ((rel == relocs
 		      || rel[-1].r_offset != rel->r_offset
 		      || r_type != R_MIPS_64
 		      || ELF_R_TYPE(abfd, rel[-1].r_info) != R_MIPS_GPREL32)
-		      && MIPS_ELF_READONLY_SECTION (sec))
+		      && MIPS_ELF_READONLY_SECTION (sec)
+		      && !((r_type == R_MIPS_32 || r_type == R_MIPS_64)
+		           && strcmp(sec->name, ".eh_frame") == 0))
 		    {
 		      /* We tell the dynamic linker that there are
 		         relocations against the text segment.  */
Index: external/gpl3/binutils/dist/gas/config/tc-mips.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/external/gpl3/binutils/dist/gas/config/tc-mips.h,v
retrieving revision 1.6
diff -u -p -r1.6 tc-mips.h
--- external/gpl3/binutils/dist/gas/config/tc-mips.h	26 Oct 2016 18:42:55 -0000	1.6
+++ external/gpl3/binutils/dist/gas/config/tc-mips.h	15 Jul 2017 19:33:13 -0000
@@ -178,7 +178,7 @@ extern int mips_dwarf2_addr_size (void);
 #define DWARF2_ADDR_SIZE(bfd) mips_dwarf2_addr_size ()
 #define DWARF2_FDE_RELOC_SIZE (compact_eh ? 4 : mips_dwarf2_addr_size ())
 #define DWARF2_FDE_RELOC_ENCODING(enc) \
-  (enc | (compact_eh ? DW_EH_PE_pcrel : 0))
+  (compact_eh ? (enc)|DW_EH_PE_pcrel : DW_EH_PE_absptr)
 
 #define TARGET_USE_CFIPOP 1
 
Index: external/gpl3/gcc/dist/gcc/configure
===================================================================
RCS file: /home/joerg/repo/netbsd/src/external/gpl3/gcc/dist/gcc/configure,v
retrieving revision 1.15
diff -u -p -r1.15 configure
--- external/gpl3/gcc/dist/gcc/configure	9 Jun 2016 23:28:22 -0000	1.15
+++ external/gpl3/gcc/dist/gcc/configure	15 Jul 2017 23:46:59 -0000
@@ -22891,7 +22891,7 @@ else
   test $ac_status = 0; }; }
     then
 
-if $gcc_cv_objdump -Wf conftest.o 2>/dev/null \
+if $gcc_cv_readelf --debug-dump=frames conftest.o 2>/dev/null \
     | grep 'DW_CFA_advance_loc[24]:[ 	][ 	]*75040[ 	]' >/dev/null; then
    gcc_cv_as_cfi_advance_working=yes
 fi
Index: external/gpl3/gcc/dist/gcc/configure.ac
===================================================================
RCS file: /home/joerg/repo/netbsd/src/external/gpl3/gcc/dist/gcc/configure.ac,v
retrieving revision 1.13
diff -u -p -r1.13 configure.ac
--- external/gpl3/gcc/dist/gcc/configure.ac	9 Jun 2016 23:28:22 -0000	1.13
+++ external/gpl3/gcc/dist/gcc/configure.ac	15 Jul 2017 23:46:49 -0000
@@ -2693,7 +2693,7 @@ gcc_GAS_CHECK_FEATURE([working cfi advan
 	.cfi_adjust_cfa_offset 128
 	.cfi_endproc],
 [[
-if $gcc_cv_objdump -Wf conftest.o 2>/dev/null \
+if $gcc_cv_readelf --debug-dump=frames conftest.o 2>/dev/null \
     | grep 'DW_CFA_advance_loc[24]:[ 	][ 	]*75040[ 	]' >/dev/null; then
    gcc_cv_as_cfi_advance_working=yes
 fi
Index: external/gpl3/gcc/dist/gcc/varasm.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/external/gpl3/gcc/dist/gcc/varasm.c,v
retrieving revision 1.1.1.6
diff -u -p -r1.1.1.6 varasm.c
--- external/gpl3/gcc/dist/gcc/varasm.c	7 Jun 2016 05:58:06 -0000	1.1.1.6
+++ external/gpl3/gcc/dist/gcc/varasm.c	14 Jul 2017 22:14:10 -0000
@@ -978,11 +978,17 @@ decode_reg_name (const char *name)
 }
 
 
-/* Return true if DECL's initializer is suitable for a BSS section.  */
+/*
+ * Return true if DECL's initializer is suitable for a BSS section.
+ * If there is an explicit section name attribute, assume that it is not
+ * for a BSS section, independent of the name.
+ */
 
 bool
 bss_initializer_p (const_tree decl)
 {
+  if (DECL_SECTION_NAME (decl) != NULL)
+    return false;
   return (DECL_INITIAL (decl) == NULL
 	  /* In LTO we have no errors in program; error_mark_node is used
 	     to mark offlined constructors.  */
@@ -6402,7 +6408,7 @@ categorize_decl_for_section (const_tree 
 	ret = SECCAT_BSS;
       else if (! TREE_READONLY (decl)
 	       || TREE_SIDE_EFFECTS (decl)
-	       || ! TREE_CONSTANT (DECL_INITIAL (decl)))
+	       || (DECL_INITIAL(decl) != NULL && ! TREE_CONSTANT (DECL_INITIAL (decl))))
 	{
 	  /* Here the reloc_rw_mask is not testing whether the section should
 	     be read-only or not, but whether the dynamic link will have to
@@ -6446,6 +6452,7 @@ categorize_decl_for_section (const_tree 
 	 no concept of a read-only thread-local-data section.  */
       if (ret == SECCAT_BSS
 	       || (flag_zero_initialized_in_bss
+		   && DECL_INITIAL(decl) != NULL
 		   && initializer_zerop (DECL_INITIAL (decl))))
 	ret = SECCAT_TBSS;
       else
Index: external/gpl3/gcc/dist/gcc/config/mips/netbsd.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/external/gpl3/gcc/dist/gcc/config/mips/netbsd.h,v
retrieving revision 1.9
diff -u -p -r1.9 netbsd.h
--- external/gpl3/gcc/dist/gcc/config/mips/netbsd.h	25 Feb 2017 21:16:50 -0000	1.9
+++ external/gpl3/gcc/dist/gcc/config/mips/netbsd.h	15 Jul 2017 02:04:34 -0000
@@ -228,4 +228,4 @@ along with GCC; see the file COPYING3.  
 #define WINT_TYPE "int"
 
 #undef TARGET_WRITABLE_EH_FRAME
-#define TARGET_WRITABLE_EH_FRAME (flag_pic && TARGET_SHARED)
+#define TARGET_WRITABLE_EH_FRAME 0
Index: lib/csu/arch/mips/crtend.S
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/csu/arch/mips/crtend.S,v
retrieving revision 1.3
diff -u -p -r1.3 crtend.S
--- lib/csu/arch/mips/crtend.S	5 Sep 2013 00:28:11 -0000	1.3
+++ lib/csu/arch/mips/crtend.S	15 Jul 2017 21:11:46 -0000
@@ -46,7 +46,7 @@ __CTOR_LIST_END__:
 __DTOR_LIST_END__:
 	.word		0
 
-	.section	.eh_frame, "aw", @progbits
+	.section	.eh_frame, "a", @progbits
 	.p2align	 PTR_SCALESHIFT
 	.space		_MIPS_SZPTR / 8
 
Index: lib/csu/common/crtbegin.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/csu/common/crtbegin.c,v
retrieving revision 1.13
diff -u -p -r1.13 crtbegin.c
--- lib/csu/common/crtbegin.c	29 Jun 2016 11:16:47 -0000	1.13
+++ lib/csu/common/crtbegin.c	15 Jul 2017 23:08:34 -0000
@@ -57,11 +57,7 @@ __dso_hidden void *__dso_handle;
 #endif
 
 #if !defined(__ARM_EABI__) || defined(__ARM_DWARF_EH__)
-__dso_hidden
-#if !defined(__mips__)
-	const
-#endif
-	long __EH_FRAME_LIST__[0] __section(".eh_frame");
+__dso_hidden const long __EH_FRAME_LIST__[0] __section(".eh_frame");
 
 __weakref_visible void register_frame_info(const void *, const void *)
 	__weak_reference(__register_frame_info);


Home | Main Index | Thread Index | Old Index