This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[patch] Handle multiple ELF function types.
- From: Paul Brook <paul at codesourcery dot com>
- To: binutils at sourceware dot org
- Date: Tue, 3 Apr 2007 23:34:36 +0100
- Subject: [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