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]

[patch] Handle multiple ELF function types.


The attached patch addresses the issue raised in
http://sourceware.org/ml/binutils/2007-01/msg00257.html

ARM has multiple ELF functions types[1] (STT_FUNC and STT_ARM_TFUNC). For most 
purposes these are the same, the differences are in the exact value used when 
resolving relocations against these symbols.

In elflink.c there are several places that want to know if something is a 
function symbol, as this influences behavior when there are multiple 
definitions of a symbol.

The patch adds a new ELF backend hook and uses this instead of explicitly 
comparing against STT_FUNC.

It also suppresses the diagnostic about mismatching symbol types when both are 
function types. For full generality this should probably be another hook, but 
ARM is the only target with multiple function types, and it doesn't care.

Tested on arm-none-eabi, arm-linux-gnueabi and i686-pc-linux-gnu.
Ok?

Paul

[1] STT_ARM_TFUC has been removed from recent ARM ELF specifications in favour 
of encoding this information in the symbol value.  However BFD still uses the 
old representation internally.

2007-04-03  Paul Brook  <paul@codesourcery.com>

	bfd/
	* elf.c (_bfd_elf_is_function_type): New function.
	* elflink.c (_bfd_elf_merge_symbol): Use bed->is_function_type.
	(_bfd_elf_dynamic_symbol_p, _bfd_elf_symbol_refs_local_p,
	is_global_data_symbol_definition, elf_link_add_object_symbols): Ditto.
	* elf-bfd.h (elf_backend_data): Add is_function_type.
	(_bfd_elf_is_function_type): Add prototype.
	* elfxx-target.h (elf_backend_is_function_type): Add default
	definition.
	(elfNN_bed): Add elf_backend_is_function_type.
	* elf32-arm.c (elf32_arm_is_function_type): New function.
	(elf_backend_is_function_type): Define.

	ld/testsuite/
	* ld-arm/preempt-app.s: New test.
	* ld-arm/preempt-app.sym: New.
	* ld-arm/arm-elf.exp: Add preempt-app.
Index: bfd/elf-bfd.h
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/elf-bfd.h,v
retrieving revision 1.230
diff -u -p -r1.230 elf-bfd.h
--- bfd/elf-bfd.h	14 Mar 2007 02:56:44 -0000	1.230
+++ bfd/elf-bfd.h	3 Apr 2007 22:08:08 -0000
@@ -1050,6 +1050,9 @@ struct elf_backend_data
   /* Return TRUE if symbol should be hashed in the `.gnu.hash' section.  */
   bfd_boolean (*elf_hash_symbol) (struct elf_link_hash_entry *);
 
+  /* Return TRUE is type is a function symbol type.  */
+  bfd_boolean (*is_function_type) (unsigned int type);
+
   /* Used to handle bad SHF_LINK_ORDER input.  */
   bfd_error_handler_type link_order_error_handler;
 
@@ -1919,6 +1922,8 @@ extern struct elf_segment_map * _bfd_elf
 extern bfd_boolean _bfd_elf_map_sections_to_segments
   (bfd *, struct bfd_link_info *);
 
+extern bfd_boolean _bfd_elf_is_function_type (unsigned int);
+
 /* Exported interface for writing elf corefile notes. */
 extern char *elfcore_write_note
   (bfd *, char *, int *, const char *, int, const void *, int);
Index: bfd/elf.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/elf.c,v
retrieving revision 1.382
diff -u -p -r1.382 elf.c
--- bfd/elf.c	29 Mar 2007 14:37:02 -0000	1.382
+++ bfd/elf.c	3 Apr 2007 22:08:08 -0000
@@ -9167,3 +9167,12 @@ _bfd_elf_set_osabi (bfd * abfd,
 
   i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
 }
+
+
+/* Return TRUE for STT_FUNC.  */
+
+bfd_boolean
+_bfd_elf_is_function_type (unsigned int type)
+{
+  return (type == STT_FUNC);
+}
Index: bfd/elf32-arm.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/elf32-arm.c,v
retrieving revision 1.109
diff -u -p -r1.109 elf32-arm.c
--- bfd/elf32-arm.c	26 Mar 2007 12:22:59 -0000	1.109
+++ bfd/elf32-arm.c	3 Apr 2007 22:08:08 -0000
@@ -10557,6 +10557,13 @@ elf32_arm_additional_program_headers (bf
     return 0;
 }
 
+/* We have two function types: STT_FUNC and STT_ARM_TFUNC.  */
+static bfd_boolean
+elf32_arm_is_function_type (unsigned int type)
+{
+  return (type == STT_FUNC) || (type == STT_ARM_TFUNC);
+}
+
 /* We use this to override swap_symbol_in and swap_symbol_out.  */
 const struct elf_size_info elf32_arm_size_info = {
   sizeof (Elf32_External_Ehdr),
@@ -10643,6 +10650,7 @@ const struct elf_size_info elf32_arm_siz
   elf32_arm_output_arch_local_syms
 #define elf_backend_begin_write_processing \
     elf32_arm_begin_write_processing
+#define elf_backend_is_function_type		elf32_arm_is_function_type 
 
 #define elf_backend_can_refcount    1
 #define elf_backend_can_gc_sections 1
Index: bfd/elflink.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/elflink.c,v
retrieving revision 1.254
diff -u -p -r1.254 elflink.c
--- bfd/elflink.c	29 Mar 2007 02:38:00 -0000	1.254
+++ bfd/elflink.c	3 Apr 2007 22:08:08 -0000
@@ -947,6 +947,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
 	    && h->root.type != bfd_link_hash_undefweak
 	    && h->root.type != bfd_link_hash_common);
 
+  bed = get_elf_backend_data (abfd);
   /* When we try to create a default indirect symbol from the dynamic
      definition with the default version, we skip it if its type and
      the type of existing regular definition mismatch.  We only do it
@@ -961,7 +962,9 @@ _bfd_elf_merge_symbol (bfd *abfd,
       && (olddef || h->root.type == bfd_link_hash_common)
       && ELF_ST_TYPE (sym->st_info) != h->type
       && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
-      && h->type != STT_NOTYPE)
+      && h->type != STT_NOTYPE
+      && !(bed->is_function_type(ELF_ST_TYPE (sym->st_info))
+	   && bed->is_function_type(h->type)))
     {
       *skip = TRUE;
       return TRUE;
@@ -1152,6 +1155,11 @@ _bfd_elf_merge_symbol (bfd *abfd,
   if (olddef && newdyn)
     oldweak = FALSE;
 
+  /* Allow changes between different types of funciton symbol.  */
+  if (bed->is_function_type(ELF_ST_TYPE (sym->st_info))
+      && bed->is_function_type(h->type))
+    *type_change_ok = TRUE;
+
   /* It's OK to change the type if either the existing symbol or the
      new symbol is weak.  A type change is also OK if the old symbol
      is undefined and the new symbol is defined.  */
@@ -1198,7 +1206,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
       && (sec->flags & SEC_ALLOC) != 0
       && (sec->flags & SEC_LOAD) == 0
       && sym->st_size > 0
-      && ELF_ST_TYPE (sym->st_info) != STT_FUNC)
+      && !bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
     newdyncommon = TRUE;
   else
     newdyncommon = FALSE;
@@ -1210,14 +1218,13 @@ _bfd_elf_merge_symbol (bfd *abfd,
       && (h->root.u.def.section->flags & SEC_ALLOC) != 0
       && (h->root.u.def.section->flags & SEC_LOAD) == 0
       && h->size > 0
-      && h->type != STT_FUNC)
+      && !bed->is_function_type (h->type))
     olddyncommon = TRUE;
   else
     olddyncommon = FALSE;
 
   /* We now know everything about the old and new symbols.  We ask the
      backend to check if we can merge them.  */
-  bed = get_elf_backend_data (abfd);
   if (bed->merge_symbol
       && !bed->merge_symbol (info, sym_hash, h, sym, psec, pvalue,
 			     pold_alignment, skip, override,
@@ -1272,7 +1279,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
       && (olddef
 	  || (h->root.type == bfd_link_hash_common
 	      && (newweak
-		  || ELF_ST_TYPE (sym->st_info) == STT_FUNC))))
+		  || bed->is_function_type (ELF_ST_TYPE (sym->st_info))))))
     {
       *override = TRUE;
       newdef = FALSE;
@@ -1327,7 +1334,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
       && (newdef
 	  || (bfd_is_com_section (sec)
 	      && (oldweak
-		  || h->type == STT_FUNC)))
+		  || bed->is_function_type (h->type))))
       && olddyn
       && olddef
       && h->def_dynamic)
@@ -2640,6 +2647,8 @@ _bfd_elf_dynamic_symbol_p (struct elf_li
 			   bfd_boolean ignore_protected)
 {
   bfd_boolean binding_stays_local_p;
+  const struct elf_backend_data *bed;
+  struct elf_link_hash_table *hash_table;
 
   if (h == NULL)
     return FALSE;
@@ -2665,10 +2674,16 @@ _bfd_elf_dynamic_symbol_p (struct elf_li
       return FALSE;
 
     case STV_PROTECTED:
+      hash_table = elf_hash_table (info);
+      if (!is_elf_hash_table (hash_table))
+	return FALSE;
+
+      bed = get_elf_backend_data (hash_table->dynobj);
+
       /* Proper resolution for function pointer equality may require
 	 that these symbols perhaps be resolved dynamically, even though
 	 we should be resolving them to the current module.  */
-      if (!ignore_protected || h->type != STT_FUNC)
+      if (!ignore_protected || !bed->is_function_type (h->type))
 	binding_stays_local_p = TRUE;
       break;
 
@@ -2695,6 +2710,9 @@ _bfd_elf_symbol_refs_local_p (struct elf
 			      struct bfd_link_info *info,
 			      bfd_boolean local_protected)
 {
+  const struct elf_backend_data *bed;
+  struct elf_link_hash_table *hash_table;
+
   /* If it's a local sym, of course we resolve locally.  */
   if (h == NULL)
     return TRUE;
@@ -2731,8 +2749,14 @@ _bfd_elf_symbol_refs_local_p (struct elf
   if (ELF_ST_VISIBILITY (h->other) != STV_PROTECTED)
     return TRUE;
 
+  hash_table = elf_hash_table (info);
+  if (!is_elf_hash_table (hash_table))
+    return TRUE;
+
+  bed = get_elf_backend_data (hash_table->dynobj);
+
   /* STV_PROTECTED non-function symbols are local.  */
-  if (h->type != STT_FUNC)
+  if (!bed->is_function_type (h->type))
     return TRUE;
 
   /* Function pointer equality tests may require that STV_PROTECTED
@@ -2781,8 +2805,9 @@ is_global_data_symbol_definition (bfd *a
       && ELF_ST_BIND (sym->st_info) < STB_LOOS)
     return FALSE;
 
+  bed = get_elf_backend_data (abfd);
   /* Function symbols do not count.  */
-  if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
+  if (bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
     return FALSE;
 
   /* If the section is undefined, then so is the symbol.  */
@@ -2791,7 +2816,6 @@ is_global_data_symbol_definition (bfd *a
 
   /* If the symbol is defined in the common section, then
      it is a common definition and so does not count.  */
-  bed = get_elf_backend_data (abfd);
   if (bed->common_definition (sym))
     return FALSE;
 
@@ -3799,8 +3823,9 @@ elf_link_add_object_symbols (bfd *abfd, 
 	     if it is not a function, because it might be the version
 	     symbol itself.  FIXME: What if it isn't?  */
 	  if ((iver.vs_vers & VERSYM_HIDDEN) != 0
-	      || (vernum > 1 && (! bfd_is_abs_section (sec)
-				 || ELF_ST_TYPE (isym->st_info) == STT_FUNC)))
+	      || (vernum > 1
+		  && (!bfd_is_abs_section (sec)
+		      || bed->is_function_type (ELF_ST_TYPE (isym->st_info)))))
 	    {
 	      const char *verstr;
 	      size_t namelen, verlen, newlen;
@@ -3947,7 +3972,7 @@ elf_link_add_object_symbols (bfd *abfd, 
       if (dynamic
 	  && definition
 	  && (flags & BSF_WEAK) != 0
-	  && ELF_ST_TYPE (isym->st_info) != STT_FUNC
+	  && !bed->is_function_type (ELF_ST_TYPE (isym->st_info))
 	  && is_elf_hash_table (htab)
 	  && h->u.weakdef == NULL)
 	{
@@ -4072,7 +4097,8 @@ elf_link_add_object_symbols (bfd *abfd, 
 	     to be the size of the common symbol.  The code just above
 	     won't fix the size if a common symbol becomes larger.  We
 	     don't warn about a size change here, because that is
-	     covered by --warn-common.  */
+	     covered by --warn-common.  Allow changed between different
+	     function types.  */
 	  if (h->root.type == bfd_link_hash_common)
 	    h->size = h->root.u.c.size;
 
@@ -4414,7 +4440,7 @@ elf_link_add_object_symbols (bfd *abfd, 
 	  h = *hpp;
 	  if (h != NULL
 	      && h->root.type == bfd_link_hash_defined
-	      && h->type != STT_FUNC)
+	      && !bed->is_function_type (h->type))
 	    {
 	      *sym_hash = h;
 	      sym_hash++;
Index: bfd/elfxx-target.h
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/elfxx-target.h,v
retrieving revision 1.105
diff -u -p -r1.105 elfxx-target.h
--- bfd/elfxx-target.h	14 Mar 2007 02:56:45 -0000	1.105
+++ bfd/elfxx-target.h	3 Apr 2007 22:08:08 -0000
@@ -587,6 +587,10 @@
 #define elf_backend_hash_symbol _bfd_elf_hash_symbol
 #endif
 
+#ifndef elf_backend_is_function_type
+#define elf_backend_is_function_type _bfd_elf_is_function_type
+#endif
+
 extern const struct elf_size_info _bfd_elfNN_size_info;
 
 static struct elf_backend_data elfNN_bed =
@@ -672,6 +676,7 @@ static struct elf_backend_data elfNN_bed
   elf_backend_common_section,
   elf_backend_merge_symbol,
   elf_backend_hash_symbol,
+  elf_backend_is_function_type,
   elf_backend_link_order_error_handler,
   elf_backend_relplt_name,
   ELF_MACHINE_ALT1,
Index: ld/testsuite/ld-arm/arm-elf.exp
===================================================================
RCS file: /var/cvsroot/src-cvs/src/ld/testsuite/ld-arm/arm-elf.exp,v
retrieving revision 1.22
diff -u -p -r1.22 arm-elf.exp
--- ld/testsuite/ld-arm/arm-elf.exp	20 Mar 2007 20:19:07 -0000	1.22
+++ ld/testsuite/ld-arm/arm-elf.exp	3 Apr 2007 22:08:37 -0000
@@ -159,6 +159,10 @@ set armelftests {
     {"arm-pic-veneer" "-static -T arm.ld --pic-veneer" "" {arm-pic-veneer.s}
      {{objdump -d arm-pic-veneer.d}}
      "arm-pic-veneer"}
+    {"Preempt Thumb symbol" "tmpdir/mixed-lib.so -T arm-dyn.ld --use-blx" ""
+     {preempt-app.s}
+     {{readelf -Ds preempt-app.sym}}
+     "preempt-app"}
 }
 
 run_ld_link_tests $armelftests
Index: ld/testsuite/ld-arm/preempt-app.s
===================================================================
RCS file: ld/testsuite/ld-arm/preempt-app.s
diff -N ld/testsuite/ld-arm/preempt-app.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/preempt-app.s	3 Apr 2007 22:08:08 -0000
@@ -0,0 +1,27 @@
+	@ Preempt an ARM shared library function with a Thumb function
+	@ in the application.
+	.text
+	.p2align 4
+	.globl _start
+_start:
+	mov	ip, sp
+	stmdb	sp!, {r11, ip, lr, pc}
+	bl	lib_func1
+	ldmia	sp, {r11, sp, lr}
+	bx lr
+
+	.p2align 4
+	.globl app_func2
+	.type app_func2,%function
+app_func2:
+	bx	lr
+
+	.p2align 4
+	.globl lib_func1
+	.type lib_func1,%function
+	.thumb_func
+lib_func1:
+	bx lr
+
+	.data
+	.long data_obj
Index: ld/testsuite/ld-arm/preempt-app.sym
===================================================================
RCS file: ld/testsuite/ld-arm/preempt-app.sym
diff -N ld/testsuite/ld-arm/preempt-app.sym
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/preempt-app.sym	3 Apr 2007 22:24:26 -0000
@@ -0,0 +1,16 @@
+
+Symbol table for image:
+  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS _edata
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __bss_start__
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS _end
+   ..  ..: ........     4  OBJECT GLOBAL DEFAULT  10 data_obj
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __bss_end__
+   ..  ..: .......1    20    FUNC GLOBAL DEFAULT   6 lib_func1
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __exidx_start
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT   9 __data_start
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __end__
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __bss_start
+   ..  ..: .......0     0    FUNC GLOBAL DEFAULT   6 app_func2
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS _bss_end__
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __exidx_end

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