Patches for gcc PR 20218

Dimitry Andric dim at FreeBSD.org
Wed Nov 17 22:02:10 UTC 2010


Hi,

When I was doing my own ports sort-of-exp-run, using the binutils 2.17
branch, I encountered an issue with the glib20 port on amd64.  Some
files in it failed to link with the error:

relocation R_X86_64_PC32 against `_g_atomic_thread_init' can not be used
when making a shared object; recompile with -fPIC

After some digging, I found this to be due to gcc PR 20218, which boils
down to '__attribute__ ((visibility ("hidden"))) does not work':

   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20218

This is unfortunately *not* yet fixed in our tree.  There is a (GPLv2)
backport of the fix to the 4.2 branch in the PR, but it does not apply
cleanly to our tree, so I have fixed it up, and attached it here as
pr20218.diff.

I have run a "make universe" with this patch, and the only problem I
encountered was with ia64:

===> gnu/lib/libgcc (obj,depend,all,install)
...
building shared library libgcc_s.so.1
unwind-ia64.So(.text+0x1762): In function `_Unwind_FindEnclosingFunction':
: undefined reference to `_Unwind_FindTableEntry'
unwind-ia64.So(.text+0x1d82): In function `uw_frame_state_for':
: undefined reference to `_Unwind_FindTableEntry'
/usr/obj/ia64.ia64/home/dim/src/freebsd/stage/head/tmp/usr/bin/ld:
libgcc_s.so.1: hidden symbol `_Unwind_FindTableEntry' isn't defined
*** Error code 1

It turns out libgcc declares the _Unwind_FindTableEntry() function with
a hidden attribute in contrib/gcc/config/ia64/unwind-ia64.h, which is
fine for the glibc and VMS (!) implementations in that directory.

However, FreeBSD's _Unwind_FindTableEntry() is in libc, so the function
declaration should be stripped of its hidden attribute to make it link.
I have attached a separate patch for this as unwind-ia64.diff.

Please review and test both patches.  There could possibly be some
fallout in ports that do weird things with hidden attributes, as those
attributes have never worked before.  So if they start working again,
some link steps might fall over...
-------------- next part --------------
Index: contrib/gcc/toplev.c
===================================================================
--- contrib/gcc/toplev.c	(revision 215396)
+++ contrib/gcc/toplev.c	(working copy)
@@ -1080,9 +1080,7 @@ compile_file (void)
 
   dw2_output_indirect_constants ();
 
-  /* Flush any pending external directives.  cgraph did this for
-     assemble_external calls from the front end, but the RTL
-     expander can also generate them.  */
+  /* Flush any pending external directives.  */
   process_pending_assemble_externals ();
 
   /* Attach a special .ident directive to the end of the file to identify
Index: contrib/gcc/cgraphunit.c
===================================================================
--- contrib/gcc/cgraphunit.c	(revision 215396)
+++ contrib/gcc/cgraphunit.c	(working copy)
@@ -1536,8 +1536,6 @@ cgraph_optimize (void)
       return;
     }
 
-  process_pending_assemble_externals ();
-
   /* Frontend may output common variables after the unit has been finalized.
      It is safe to deal with them here as they are always zero initialized.  */
   cgraph_varpool_analyze_pending_decls ();
Index: contrib/gcc/varasm.c
===================================================================
--- contrib/gcc/varasm.c	(revision 215396)
+++ contrib/gcc/varasm.c	(working copy)
@@ -126,7 +126,6 @@ static unsigned HOST_WIDE_INT array_size_for_const
 static unsigned min_align (unsigned, unsigned);
 static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int);
 static void globalize_decl (tree);
-static void maybe_assemble_visibility (tree);
 #ifdef BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_BSS
 static void asm_output_bss (FILE *, tree, const char *,
@@ -1957,11 +1956,10 @@ assemble_external (tree decl ATTRIBUTE_UNUSED)
   if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
     return;
 
-  if (flag_unit_at_a_time)
-    pending_assemble_externals = tree_cons (0, decl,
-					    pending_assemble_externals);
-  else
-    assemble_external_real (decl);
+  /* We want to output external symbols at very last to check if they
+     are references or not.  */
+  pending_assemble_externals = tree_cons (0, decl,
+					  pending_assemble_externals);
 #endif
 }
 
@@ -5064,13 +5062,18 @@ default_assemble_visibility (tree decl, int vis)
 
 /* A helper function to call assemble_visibility when needed for a decl.  */
 
-static void
+int
 maybe_assemble_visibility (tree decl)
 {
   enum symbol_visibility vis = DECL_VISIBILITY (decl);
 
   if (vis != VISIBILITY_DEFAULT)
-    targetm.asm_out.visibility (decl, vis);
+    {
+      targetm.asm_out.visibility (decl, vis);
+      return 1;
+    }
+  else
+    return 0;
 }
 
 /* Returns 1 if the target configuration supports defining public symbols
@@ -6224,4 +6227,19 @@ output_object_blocks (void)
   htab_traverse (object_block_htab, output_object_block_htab, NULL);
 }
 
+/* Emit text to declare externally defined symbols. It is needed to
+   properly support non-default visibility.  */
+void
+default_elf_asm_output_external (FILE *file ATTRIBUTE_UNUSED,
+				 tree decl,
+				 const char *name ATTRIBUTE_UNUSED)
+{
+  /* We output the name if and only if TREE_SYMBOL_REFERENCED is
+     set in order to avoid putting out names that are never really
+     used. */
+  if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
+      && targetm.binds_local_p (decl))
+    maybe_assemble_visibility (decl);
+}
+
 #include "gt-varasm.h"
Index: contrib/gcc/output.h
===================================================================
--- contrib/gcc/output.h	(revision 215396)
+++ contrib/gcc/output.h	(working copy)
@@ -200,9 +200,9 @@ extern void assemble_variable (tree, int, int, int
    DONT_OUTPUT_DATA is from assemble_variable.  */
 extern void align_variable (tree decl, bool dont_output_data);
 
-/* Output something to declare an external symbol to the assembler.
-   (Most assemblers don't need this, so we normally output nothing.)
-   Do nothing if DECL is not external.  */
+/* Queue for outputing something to declare an external symbol to the
+   assembler.  (Most assemblers don't need this, so we normally output
+   nothing.)  Do nothing if DECL is not external.  */
 extern void assemble_external (tree);
 
 /* Assemble code to leave SIZE bytes of zeros.  */
@@ -607,6 +607,10 @@ extern void default_file_start (void);
 extern void file_end_indicate_exec_stack (void);
 extern bool default_valid_pointer_mode (enum machine_mode);
 
+extern void default_elf_asm_output_external (FILE *file, tree,
+					     const char *);
+extern int maybe_assemble_visibility (tree);
+
 extern int default_address_cost (rtx);
 
 /* dbxout helper functions */
Index: contrib/gcc/config/elfos.h
===================================================================
--- contrib/gcc/config/elfos.h	(revision 215396)
+++ contrib/gcc/config/elfos.h	(working copy)
@@ -496,3 +496,13 @@ Boston, MA 02110-1301, USA.  */
         fprintf ((FILE), "\"\n");					\
     }									\
   while (0)
+
+/* A C statement (sans semicolon) to output to the stdio stream STREAM
+   any text necessary for declaring the name of an external symbol
+   named NAME whch is referenced in this compilation but not defined.
+   It is needed to properly support non-default visibility.  */
+
+#ifndef ASM_OUTPUT_EXTERNAL
+#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \
+  default_elf_asm_output_external (FILE, DECL, NAME)
+#endif
Index: contrib/gcc/config/ia64/ia64.c
===================================================================
--- contrib/gcc/config/ia64/ia64.c	(revision 215396)
+++ contrib/gcc/config/ia64/ia64.c	(working copy)
@@ -250,10 +250,6 @@ static section *ia64_select_rtx_section (enum mach
 static void ia64_output_dwarf_dtprel (FILE *, int, rtx)
      ATTRIBUTE_UNUSED;
 static unsigned int ia64_section_type_flags (tree, const char *, int);
-static void ia64_hpux_add_extern_decl (tree decl)
-     ATTRIBUTE_UNUSED;
-static void ia64_hpux_file_end (void)
-     ATTRIBUTE_UNUSED;
 static void ia64_init_libfuncs (void)
      ATTRIBUTE_UNUSED;
 static void ia64_hpux_init_libfuncs (void)
@@ -5015,49 +5011,6 @@ ia64_secondary_reload_class (enum reg_class class,
 }
 
 
-/* Emit text to declare externally defined variables and functions, because
-   the Intel assembler does not support undefined externals.  */
-
-void
-ia64_asm_output_external (FILE *file, tree decl, const char *name)
-{
-  int save_referenced;
-
-  /* GNU as does not need anything here, but the HP linker does need
-     something for external functions.  */
-
-  if (TARGET_GNU_AS
-      && (!TARGET_HPUX_LD
-	  || TREE_CODE (decl) != FUNCTION_DECL
-	  || strstr (name, "__builtin_") == name))
-    return;
-
-  /* ??? The Intel assembler creates a reference that needs to be satisfied by
-     the linker when we do this, so we need to be careful not to do this for
-     builtin functions which have no library equivalent.  Unfortunately, we
-     can't tell here whether or not a function will actually be called by
-     expand_expr, so we pull in library functions even if we may not need
-     them later.  */
-  if (! strcmp (name, "__builtin_next_arg")
-      || ! strcmp (name, "alloca")
-      || ! strcmp (name, "__builtin_constant_p")
-      || ! strcmp (name, "__builtin_args_info"))
-    return;
-
-  if (TARGET_HPUX_LD)
-    ia64_hpux_add_extern_decl (decl);
-  else
-    {
-      /* assemble_name will set TREE_SYMBOL_REFERENCED, so we must save and
-         restore it.  */
-      save_referenced = TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl));
-      if (TREE_CODE (decl) == FUNCTION_DECL)
-        ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
-      (*targetm.asm_out.globalize_label) (file, name);
-      TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) = save_referenced;
-    }
-}
-
 /* Parse the -mfixed-range= option string.  */
 
 static void
@@ -9223,55 +9176,33 @@ ia64_hpux_function_arg_padding (enum machine_mode
    return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
 }
 
-/* Linked list of all external functions that are to be emitted by GCC.
-   We output the name if and only if TREE_SYMBOL_REFERENCED is set in
-   order to avoid putting out names that are never really used.  */
+/* Emit text to declare externally defined variables and functions, because
+   the Intel assembler does not support undefined externals.  */
 
-struct extern_func_list GTY(())
+void
+ia64_asm_output_external (FILE *file, tree decl, const char *name)
 {
-  struct extern_func_list *next;
-  tree decl;
-};
-
-static GTY(()) struct extern_func_list *extern_func_head;
-
-static void
-ia64_hpux_add_extern_decl (tree decl)
-{
-  struct extern_func_list *p = ggc_alloc (sizeof (struct extern_func_list));
-
-  p->decl = decl;
-  p->next = extern_func_head;
-  extern_func_head = p;
-}
-
-/* Print out the list of used global functions.  */
-
-static void
-ia64_hpux_file_end (void)
-{
-  struct extern_func_list *p;
-
-  for (p = extern_func_head; p; p = p->next)
+  /* We output the name if and only if TREE_SYMBOL_REFERENCED is
+     set in order to avoid putting out names that are never really
+     used. */
+  if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
     {
-      tree decl = p->decl;
-      tree id = DECL_ASSEMBLER_NAME (decl);
+      /* maybe_assemble_visibility will return 1 if the assembler
+	 visibility directive is outputed.  */
+      int need_visibility = ((*targetm.binds_local_p) (decl)
+			     && maybe_assemble_visibility (decl));
 
-      gcc_assert (id);
-
-      if (!TREE_ASM_WRITTEN (decl) && TREE_SYMBOL_REFERENCED (id))
-        {
-	  const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
-
-	  TREE_ASM_WRITTEN (decl) = 1;
-	  (*targetm.asm_out.globalize_label) (asm_out_file, name);
-	  fputs (TYPE_ASM_OP, asm_out_file);
-	  assemble_name (asm_out_file, name);
-	  fprintf (asm_out_file, "," TYPE_OPERAND_FMT "\n", "function");
-        }
+      /* GNU as does not need anything here, but the HP linker does
+	 need something for external functions.  */
+      if ((TARGET_HPUX_LD || !TARGET_GNU_AS)
+	  && TREE_CODE (decl) == FUNCTION_DECL)
+	{
+	  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
+	  (*targetm.asm_out.globalize_label) (file, name);
+	}
+      else if (need_visibility && !TARGET_GNU_AS)
+	(*targetm.asm_out.globalize_label) (file, name);
     }
-
-  extern_func_head = 0;
 }
 
 /* Set SImode div/mod functions, init_integral_libfuncs only initializes
Index: contrib/gcc/config/ia64/hpux.h
===================================================================
--- contrib/gcc/config/ia64/hpux.h	(revision 215396)
+++ contrib/gcc/config/ia64/hpux.h	(working copy)
@@ -144,10 +144,6 @@ do {								\
    definitions, so do not use them in gthr-posix.h.  */
 #define GTHREAD_USE_WEAK 0
 
-/* Put out the needed function declarations at the end.  */
-
-#define TARGET_ASM_FILE_END ia64_hpux_file_end
-
 #undef CTORS_SECTION_ASM_OP
 #define CTORS_SECTION_ASM_OP  "\t.section\t.init_array,\t\"aw\",\"init_array\""
 
-------------- next part --------------
Index: contrib/gcc/config/ia64/unwind-ia64.h
===================================================================
--- contrib/gcc/config/ia64/unwind-ia64.h	(revision 215423)
+++ contrib/gcc/config/ia64/unwind-ia64.h	(working copy)
@@ -19,6 +19,13 @@
    the Free Software Foundation, 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.  */
 
+#ifdef __FreeBSD__
+/* On FreeBSD, _Unwind_FindTableEntry is in libc, and must not be hidden here. */
+#define ATTRIBUTE_HIDDEN
+#else
+#define ATTRIBUTE_HIDDEN  __attribute__ ((__visibility__ ("hidden")))
+#endif
+
 struct unw_table_entry
 {
   unsigned long start_offset;
@@ -29,4 +36,4 @@ struct unw_table_entry
 extern struct unw_table_entry *
 _Unwind_FindTableEntry (void *pc, unsigned long *segment_base,
 			unsigned long *gp)
-			__attribute__ ((__visibility__ ("hidden")));
+			ATTRIBUTE_HIDDEN;


More information about the freebsd-current mailing list