This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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]

IA64 HP-UX patch for external function declarations


The HP Linker is very fussy about declaring functions to be external.

If you don't declare a function to be external and it is in a shared
library and you try to call it you can get a seg fault.

If you declare a function to be external but never define it (or use it)
you will get an unsatisfied symbol error when linking even thought it
isn't really needed.

This causes problems because GCC can call ASM_OUTPUT_EXTERNAL for a
function and then because the function is never used, or always inlined,
or the call is optimized away, it can decide not to output the function.
If ASM_OUTPUT_EXTERNAL itself marks a function as used then we wind up
including functions that are not really needed.

It also causes problems with the GCC test suite where a test calls
link_error() and assumes that optimization will make the call go away
and that the test can be compiled correctly without the link_error()
routine when optimization is turned on.  The test will fail because
ASM_OUTPUT_EXTERNAL will output an external declaration but not the
actual routine.

Anyway, I stole some code from the i386 config directory to have
ASM_OUTPUT_EXTERNAL build a list of external functions and then only put
out the ones that get used at the end of the compilation.

I do this based on the value of TARGET_HPUX_LD which I created, I
considered using !TARGET_GNU_LD but wasn't sure if the assumption that
!TARGET_GNU_LD == TARGET_HPUX_LD was true, there may be other linkers.

Comments?

Steve Ellcey
sje@cup.hp.com


2002-09-06  Steve Ellcey  <sje@cup.hp.com>

	* config/ia64/hpux.h (TARGET_HPUX_LD): New, define true.
	(ASM_FILE_END) New.
	* config/ia64/ia64.h (TARGET_HPUX_LD): New, define false.
	* config/ia64/ia64-protos.h (ia64_hpux_asm_file_end): New.
	* config/ia64/ia64.c (ia64_asm_output_external): Create list
	of external functions if TARGET_HPUX_LD is true.
	(ia64_hpux_add_extern_decl): New, routine to put names on
	list of external functions.
	(ia64_hpux_asm_file_end): Put out declarations for external
	functions if and only if they are used.

*** gcc.orig/gcc/config/ia64/hpux.h	Fri Sep  6 10:43:11 2002
--- gcc/gcc/config/ia64/hpux.h	Fri Sep  6 11:12:21 2002
*************** do {							\
*** 127,129 ****
--- 127,140 ----
  
  #define REGISTER_TARGET_PRAGMAS(PFILE) \
    cpp_register_pragma (PFILE, 0, "builtin", ia64_hpux_handle_builtin_pragma)
+ 
+ /* Tell ia64.c that we are using the HP linker and we should delay output of
+    function extern declarations so that we don't output them for functions
+    which are never used (and may not be defined).  */
+ 
+ #undef TARGET_HPUX_LD
+ #define TARGET_HPUX_LD	1
+ 
+ /* Put out the needed function declarations at the end.  */
+ 
+ #define ASM_FILE_END(STREAM) ia64_hpux_asm_file_end(STREAM)
*** gcc.orig/gcc/config/ia64/ia64.h	Fri Sep  6 11:06:16 2002
--- gcc/gcc/config/ia64/ia64.h	Fri Sep  6 11:10:15 2002
*************** extern int ia64_tls_size;
*** 127,132 ****
--- 127,134 ----
  #define TARGET_TLS22		(ia64_tls_size == 22)
  #define TARGET_TLS64		(ia64_tls_size == 64)
  
+ #define TARGET_HPUX_LD		0
+ 
  /* This macro defines names of command options to set and clear bits in
     `target_flags'.  Its definition is an initializer with a subgrouping for
     each command option.  */
*** gcc.orig/gcc/config/ia64/ia64-protos.h	Fri Sep  6 10:46:05 2002
--- gcc/gcc/config/ia64/ia64-protos.h	Fri Sep  6 10:46:53 2002
*************** extern enum direction ia64_hpux_function
*** 148,150 ****
--- 148,152 ----
  #ifdef GCC_C_PRAGMA_H
  extern void ia64_hpux_handle_builtin_pragma PARAMS ((cpp_reader *));
  #endif
+ 
+ extern void ia64_hpux_asm_file_end PARAMS ((FILE *));
*** gcc.orig/gcc/config/ia64/ia64.c	Fri Sep  6 10:47:08 2002
--- gcc/gcc/config/ia64/ia64.c	Fri Sep  6 11:23:27 2002
*************** static void ia64_aix_unique_section PARA
*** 171,176 ****
--- 171,179 ----
  static void ia64_aix_select_rtx_section PARAMS ((enum machine_mode, rtx,
  					         unsigned HOST_WIDE_INT))
       ATTRIBUTE_UNUSED;
+ 
+ static void ia64_hpux_add_extern_decl PARAMS ((const char *name))
+      ATTRIBUTE_UNUSED;
  
  /* Table of valid machine attributes.  */
  static const struct attribute_spec ia64_attribute_table[] =
*************** ia64_asm_output_external (file, decl, na
*** 4039,4046 ****
  {
    int save_referenced;
  
!   /* GNU as does not need anything here.  */
!   if (TARGET_GNU_AS)
      return;
  
    /* ??? The Intel assembler creates a reference that needs to be satisfied by
--- 4042,4054 ----
  {
    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
*************** ia64_asm_output_external (file, decl, na
*** 4055,4067 ****
        || ! strcmp (name, "__builtin_args_info"))
      return;
  
!   /* 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.  */
--- 4063,4080 ----
        || ! strcmp (name, "__builtin_args_info"))
      return;
  
!   if (TARGET_HPUX_LD)
!     ia64_hpux_add_extern_decl (name);
!   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.  */
*************** ia64_hpux_function_arg_padding (mode, ty
*** 8050,8055 ****
--- 8063,8121 ----
         : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY)
        ? downward : upward);
  }
+ 
+ /* 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.  */
+ 
+ struct extern_func_list
+ {
+   struct extern_func_list *next; /* next external */
+   char *name;                    /* name of the external */
+ } *extern_func_head = 0;
+ 
+ static void
+ ia64_hpux_add_extern_decl (name)
+         const char *name;
+ {
+   struct extern_func_list *p;
+ 
+   p = (struct extern_func_list *) xmalloc (sizeof (struct extern_func_list));
+   p->name = xmalloc (strlen (name) + 1);
+   strcpy(p->name, name);
+   p->next = extern_func_head;
+   extern_func_head = p;
+ }
+ 
+ /* Print out the list of used global functions.  */
+ 
+ void
+ ia64_hpux_asm_file_end (file)
+ 	FILE *file;
+ {
+   while (extern_func_head)
+     {
+       char *real_name;
+       tree decl;
+ 
+       real_name = (* targetm.strip_name_encoding) (extern_func_head->name);
+       decl = get_identifier (real_name);
+       if (decl && ! TREE_ASM_WRITTEN (decl) && TREE_SYMBOL_REFERENCED (decl))
+         {
+ 	  if (real_name[strlen (real_name) - 1] == '#')
+ 	    real_name[strlen (real_name) - 1] = 0;
+ 	  TREE_ASM_WRITTEN (decl) = 1;
+ 	  (*targetm.asm_out.globalize_label) (file, real_name);
+ 	  fprintf (file, "%s", TYPE_ASM_OP);
+ 	  assemble_name (file, real_name);
+ 	  putc (',', file);
+ 	  fprintf (file, TYPE_OPERAND_FMT, "function");
+ 	  putc ('\n', file);
+         }
+       extern_func_head = extern_func_head->next;
+     }
+ }
+ 
  
  /* Switch to the section to which we should output X.  The only thing
     special we do here is to honor small data.  */


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