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]

Re: [patch] Arm v4t Thumb shared libraries.


Hi Paul,

When I apply this patch I am getting linking errors when linking uClibc in Thumb mode. The testcase is uploaded here

http://source.mvista.com/~kraj/thumb-ld-segfault.tar.bz2

Thanks

Khem

Paul Brook said the following on 8/17/2006 2:36 PM:
The current arm-linux PLT sequence ends with the equivalent of

ldr pc, [ip]

This sequence is not interworking safe on armv4t hardware. To enable use of Thumb in shared libraries there are two options:

a) Use a new PLT sequence. Because we only have one scratch register and the requirements of the lazy resolver this means doubling the size of all PLT, entries and probably breaks prelinking.

b) Make sure that all functions exported from shared libraries are entered in Arm mode, inserting stubs as neccessary, thus avoiding the whole issue. This also means that prelinking and applications which do not use Thumb are uneffected.

The attached patch implements (b). It reuses the existing infrastructure for generating arm->thumb stubs.

Ok?

Paul

2006-08-17 Paul Brook <paul@codesourcery.com>

	bfd/
	* elf32-arm.c (elf32_arm_link_hash_entry): Add export_glue.
	(elf32_arm_link_hash_newfunc): Initialize export_glue.
	(record_arm_to_thumb_glue): Return stub symbol.
	(elf32_arm_create_thumb_stub): New function.
	(elf32_arm_to_thumb_stub): Use it.
	(elf32_arm_to_thumb_export_stub): New function.
	(elf32_arm_begin_write_processing): New function.
	(allocate_dynrelocs): Allocate Arm stubs.
	(elf_backend_begin_write_processing): Define.
	(elf32_arm_symbian_begin_write_processing): Remove ATTRIBUTE_UNUSED.
	Call elf32_arm_begin_write_processing.

	ld/
	* emultempl/armelf.em (arm_elf_before_allocation): Call
	gld${EMULATION_NAME}_before_allocation after setting interworking bfd.

ld/testsuite/
* ld-arm/arm-elf.exp (armelftests): Add armthumb-lib.so. Add
-use-blx to mixed-lib.so
* ld-arm/armthumb-lib.d: New file.
* ld-arm/armthumb-lib.sym: New file.
------------------------------------------------------------------------


Index: bfd/elf32-arm.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/elf32-arm.c,v
retrieving revision 1.70.2.7
diff -u -p -r1.70.2.7 elf32-arm.c
--- bfd/elf32-arm.c 19 Jun 2006 14:22:33 -0000 1.70.2.7
+++ bfd/elf32-arm.c 17 Aug 2006 15:29:54 -0000
@@ -2089,6 +2089,10 @@ struct elf32_arm_link_hash_entry
#define GOT_TLS_GD 2
#define GOT_TLS_IE 4
unsigned char tls_type;
+
+ /* The symbol marking the real symbol location for exported thumb
+ symbols with Arm stubs. */
+ struct elf_link_hash_entry *export_glue;
};
/* Traverse an arm ELF linker hash table. */
@@ -2200,6 +2204,7 @@ elf32_arm_link_hash_newfunc (struct bfd_
ret->tls_type = GOT_UNKNOWN;
ret->plt_thumb_refcount = 0;
ret->plt_got_offset = -1;
+ ret->export_glue = NULL;
}
return (struct bfd_hash_entry *) ret;
@@ -2578,7 +2583,9 @@ bfd_elf32_arm_allocate_interworking_sect
return TRUE;
}
-static void
+/* Allocate space and symbols for calling a Thumb function from Arm mode.
+ returns the symbol identifying teh stub. */
+static struct elf_link_hash_entry *
record_arm_to_thumb_glue (struct bfd_link_info * link_info,
struct elf_link_hash_entry * h)
{
@@ -2613,7 +2620,7 @@ record_arm_to_thumb_glue (struct bfd_lin
{
/* We've already seen this guy. */
free (tmp_name);
- return;
+ return myh;
}
/* The only trick here is using hash_table->arm_glue_size as the value.
@@ -2636,7 +2643,7 @@ record_arm_to_thumb_glue (struct bfd_lin
else
globals->arm_glue_size += ARM2THUMB_STATIC_GLUE_SIZE;
- return;
+ return myh;
}
static void
@@ -3191,30 +3198,25 @@ elf32_thumb_to_arm_stub (struct bfd_link
return TRUE;
}
-/* Arm code calling a Thumb function. */
+/* Populate an Arm to Thumb stub. Returns the stub symbol. */
-static int
-elf32_arm_to_thumb_stub (struct bfd_link_info * info,
- const char * name,
- bfd * input_bfd,
- bfd * output_bfd,
- asection * input_section,
- bfd_byte * hit_data,
- asection * sym_sec,
- bfd_vma offset,
- bfd_signed_vma addend,
- bfd_vma val)
+static struct elf_link_hash_entry *
+elf32_arm_create_thumb_stub (struct bfd_link_info * info,
+ const char * name,
+ bfd * input_bfd,
+ bfd * output_bfd,
+ asection * sym_sec,
+ bfd_vma val,
+ asection *s)
{
- unsigned long int tmp;
bfd_vma my_offset;
- asection * s;
long int ret_offset;
struct elf_link_hash_entry * myh;
struct elf32_arm_link_hash_table * globals;
myh = find_arm_glue (info, name, input_bfd);
if (myh == NULL)
- return FALSE;
+ return NULL;
globals = elf32_arm_hash_table (info);
@@ -3222,11 +3224,6 @@ elf32_arm_to_thumb_stub (struct bfd_link
BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
my_offset = myh->root.u.def.value;
- s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
- ARM2THUMB_GLUE_SECTION_NAME);
- BFD_ASSERT (s != NULL);
- BFD_ASSERT (s->contents != NULL);
- BFD_ASSERT (s->output_section != NULL);
if ((my_offset & 0x01) == 0x01)
{
@@ -3280,6 +3277,47 @@ elf32_arm_to_thumb_stub (struct bfd_link
BFD_ASSERT (my_offset <= globals->arm_glue_size);
+ return myh;
+}
+
+/* Arm code calling a Thumb function. */
+
+static int
+elf32_arm_to_thumb_stub (struct bfd_link_info * info,
+ const char * name,
+ bfd * input_bfd,
+ bfd * output_bfd,
+ asection * input_section,
+ bfd_byte * hit_data,
+ asection * sym_sec,
+ bfd_vma offset,
+ bfd_signed_vma addend,
+ bfd_vma val)
+{
+ unsigned long int tmp;
+ bfd_vma my_offset;
+ asection * s;
+ long int ret_offset;
+ struct elf_link_hash_entry * myh;
+ struct elf32_arm_link_hash_table * globals;
+
+ globals = elf32_arm_hash_table (info);
+
+ BFD_ASSERT (globals != NULL);
+ BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+ s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+ ARM2THUMB_GLUE_SECTION_NAME);
+ BFD_ASSERT (s != NULL);
+ BFD_ASSERT (s->contents != NULL);
+ BFD_ASSERT (s->output_section != NULL);
+
+ myh = elf32_arm_create_thumb_stub (info, name, input_bfd, output_bfd,
+ sym_sec, val, s);
+ if (!myh)
+ return FALSE;
+
+ my_offset = myh->root.u.def.value;
tmp = bfd_get_32 (input_bfd, hit_data);
tmp = tmp & 0xFF000000;
@@ -3299,6 +3337,63 @@ elf32_arm_to_thumb_stub (struct bfd_link
return TRUE;
}
+/* Populate Arm stub for an exported Thumb function. */
+
+static bfd_boolean
+elf32_arm_to_thumb_export_stub (struct elf_link_hash_entry *h, void * inf)
+{
+ struct bfd_link_info * info = (struct bfd_link_info *) inf;
+ asection * s;
+ struct elf_link_hash_entry * myh;
+ struct elf32_arm_link_hash_entry *eh;
+ struct elf32_arm_link_hash_table * globals;
+ asection *sec;
+ bfd_vma val;
+
+ eh = elf32_arm_hash_entry(h);
+ /* Allocate stubs for exported Thumb functions on v4t. */
+ if (eh->export_glue == NULL)
+ return TRUE;
+
+ globals = elf32_arm_hash_table (info);
+
+ BFD_ASSERT (globals != NULL);
+ BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+ s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+ ARM2THUMB_GLUE_SECTION_NAME);
+ BFD_ASSERT (s != NULL);
+ BFD_ASSERT (s->contents != NULL);
+ BFD_ASSERT (s->output_section != NULL);
+
+ sec = eh->export_glue->root.u.def.section;
+ val = eh->export_glue->root.u.def.value + sec->output_offset
+ + sec->output_section->vma;
+ myh = elf32_arm_create_thumb_stub (info, h->root.root.string,
+ h->root.u.def.section->owner,
+ globals->obfd, sec, val, s);
+ BFD_ASSERT (myh);
+ return TRUE;
+}
+
+/* Generate Arm stubs for exported Thumb symbols. */
+static void
+elf32_arm_begin_write_processing (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *link_info)
+{
+ struct elf32_arm_link_hash_table * globals;
+
+ if (!link_info)
+ return;
+
+ globals = elf32_arm_hash_table (link_info);
+ if (globals->use_blx)
+ return;
+
+ elf_link_hash_traverse (&globals->root, elf32_arm_to_thumb_export_stub,
+ link_info);
+}
+
/* Some relocations map to different relocations depending on the
target. Return the real relocation. */
static int
@@ -7462,6 +7557,36 @@ allocate_dynrelocs (struct elf_link_hash
else
h->got.offset = (bfd_vma) -1;
+ /* Allocate stubs for exported Thumb functions on v4t. */
+ if (!htab->use_blx && h->dynindx != -1
+ && ELF_ST_TYPE (h->type) == STT_ARM_TFUNC
+ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+ {
+ struct elf_link_hash_entry * th;
+ struct bfd_link_hash_entry * bh;
+ struct elf_link_hash_entry * myh;
+ char name[1024];
+ asection *s;
+ bh = NULL;
+ /* Create a new symbol to regist the real location of the function. */
+ s = h->root.u.def.section;
+ sprintf(name, "__real_%s", h->root.root.string);
+ _bfd_generic_link_add_one_symbol (info, s->owner,
+ name, BSF_GLOBAL, s,
+ h->root.u.def.value,
+ NULL, TRUE, FALSE, &bh);
+
+ myh = (struct elf_link_hash_entry *) bh;
+ myh->type = ELF_ST_INFO (STB_LOCAL, STT_ARM_TFUNC);
+ myh->forced_local = 1;
+ eh->export_glue = myh;
+ th = record_arm_to_thumb_glue (info, h);
+ /* Point the symbol at the stub. */
+ h->type = ELF_ST_INFO (ELF_ST_BIND (h->type), STT_FUNC);
+ h->root.u.def.section = th->root.u.def.section;
+ h->root.u.def.value = th->root.u.def.value & ~1;
+ }
+
if (eh->relocs_copied == NULL)
return TRUE;
@@ -9304,6 +9429,8 @@ const struct elf_size_info elf32_arm_siz
elf32_arm_additional_program_headers
#define elf_backend_output_arch_local_syms \
elf32_arm_output_arch_local_syms
+#define elf_backend_begin_write_processing \
+ elf32_arm_begin_write_processing
#define elf_backend_can_refcount 1
#define elf_backend_can_gc_sections 1
@@ -9445,8 +9572,7 @@ elf32_arm_symbian_special_sections[] =
static void
elf32_arm_symbian_begin_write_processing (bfd *abfd, - struct bfd_link_info *link_info
- ATTRIBUTE_UNUSED)
+ struct bfd_link_info *link_info)
{
/* BPABI objects are never loaded directly by an OS kernel; they are
processed by a postlinker first, into an OS-specific format. If
@@ -9457,6 +9583,7 @@ elf32_arm_symbian_begin_write_processing
recognize that the program headers should not be mapped into any
loadable segment. */
abfd->flags &= ~D_PAGED;
+ elf32_arm_begin_write_processing(abfd, link_info);
}
static bfd_boolean
Index: ld/emultempl/armelf.em
===================================================================
RCS file: /var/cvsroot/src-cvs/src/ld/emultempl/armelf.em,v
retrieving revision 1.49
diff -u -p -r1.49 armelf.em
--- ld/emultempl/armelf.em 7 Feb 2006 03:50:20 -0000 1.49
+++ ld/emultempl/armelf.em 17 Aug 2006 15:29:54 -0000
@@ -103,9 +103,6 @@ arm_elf_before_allocation (void)
{
bfd *tem;
- /* Call the standard elf routine. */
- gld${EMULATION_NAME}_before_allocation ();
-
if (link_info.input_bfds != NULL)
{
/* The interworking bfd must be the last one in the link. */
@@ -126,6 +123,9 @@ arm_elf_before_allocation (void)
}
/* We should be able to set the size of the interworking stub section. */
+ /* Call the standard elf routine. */
+ gld${EMULATION_NAME}_before_allocation ();
+
/* Here we rummage through the found bfds to collect glue information. */
/* FIXME: should this be based on a command line option? krk@cygnus.com */
{
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.11.2.5
diff -u -p -r1.11.2.5 arm-elf.exp
--- ld/testsuite/ld-arm/arm-elf.exp 19 Jun 2006 14:22:33 -0000 1.11.2.5
+++ ld/testsuite/ld-arm/arm-elf.exp 17 Aug 2006 17:21:24 -0000
@@ -77,7 +77,11 @@ set armelftests {
{"Non-pcrel function reference" "tmpdir/arm-lib.so" "" {arm-app-abs32.s}
{{objdump -fdw arm-app-abs32.d} {objdump -Rw arm-app-abs32.r}}
"arm-app-abs32"}
- {"Mixed ARM/Thumb shared library" "-shared -T arm-lib.ld" ""
+ {"Thumb shared library with ARM entry points" "-shared -T arm-lib.ld" ""
+ {mixed-lib.s}
+ {{objdump -fdw armthumb-lib.d} {readelf -Ds armthumb-lib.sym}}
+ "armthumb-lib.so"}
+ {"Mixed ARM/Thumb shared library" "-shared -T arm-lib.ld -use-blx" ""
{mixed-lib.s}
{{objdump -fdw mixed-lib.d} {objdump -Rw mixed-lib.r}
{readelf -Ds mixed-lib.sym}}
Index: ld/testsuite/ld-arm/armthumb-lib.d
===================================================================
RCS file: ld/testsuite/ld-arm/armthumb-lib.d
diff -N ld/testsuite/ld-arm/armthumb-lib.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/armthumb-lib.d 17 Aug 2006 17:23:20 -0000
@@ -0,0 +1,44 @@
+
+tmpdir/armthumb-lib.so: file format elf32-(little|big)arm
+architecture: arm, flags 0x00000150:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x.*
+
+Disassembly of section .plt:
+
+.* <.plt>:
+ .*: e52de004 str lr, \[sp, #-4\]!
+ .*: e59fe004 ldr lr, \[pc, #4\] ; .* <\.plt\+0x10>
+ .*: e08fe00e add lr, pc, lr
+ .*: e5bef008 ldr pc, \[lr, #8\]!
+ .*: .*
+ .*: e28fc6.* add ip, pc, #.* ; 0x.*
+ .*: e28cca.* add ip, ip, #.* ; 0x.*
+ .*: e5bcf.* ldr pc, \[ip, #.*\]!
+Disassembly of section .text:
+
+.* <lib_func1>:
+ .*: e1a0c00d mov ip, sp
+ .*: e92dd800 stmdb sp!, {fp, ip, lr, pc}
+ .*: ebfffff. bl .* <.text-0x..>
+ .*: e89d6800 ldmia sp, {fp, sp, lr}
+ .*: e12fff1e bx lr
+ .*: e1a00000 nop \(mov r0,r0\)
+ .*: e1a00000 nop \(mov r0,r0\)
+ .*: e1a00000 nop \(mov r0,r0\)
+
+.* <__real_lib_func2>:
+ .*: 4770 bx lr
+ .*: 46c0 nop \(mov r8, r8\)
+ .*: 46c0 nop \(mov r8, r8\)
+ .*: 46c0 nop \(mov r8, r8\)
+ .*: 46c0 nop \(mov r8, r8\)
+ .*: 46c0 nop \(mov r8, r8\)
+ .*: 46c0 nop \(mov r8, r8\)
+ .*: 46c0 nop \(mov r8, r8\)
+
+.* <lib_func2>:
+ .*: e59fc004 ldr ip, \[pc, #4\] ; 33c <lib_func2\+0xc>
+ .*: e08cc00f add ip, ip, pc
+ .*: e12fff1c bx ip
+ .*: ffffffe5 .*
Index: ld/testsuite/ld-arm/armthumb-lib.sym
===================================================================
RCS file: ld/testsuite/ld-arm/armthumb-lib.sym
diff -N ld/testsuite/ld-arm/armthumb-lib.sym
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/armthumb-lib.sym 17 Aug 2006 16:51:35 -0000
@@ -0,0 +1,18 @@
+
+Symbol table for image:
+ Num Buc: Value Size Type Bind Vis Ndx Name
+ .. ..: ........ 0 NOTYPE GLOBAL DEFAULT ABS _edata
+ .. ..: .......0 20 FUNC GLOBAL DEFAULT 6 lib_func1
+ .. ..: .......0 2 FUNC GLOBAL DEFAULT 6 lib_func2
+ .. ..: ........ 0 NOTYPE GLOBAL DEFAULT ABS _bss_end__
+ .. ..: ........ 0 NOTYPE GLOBAL DEFAULT ABS __bss_end__
+ .. ..: ........ 0 NOTYPE GLOBAL DEFAULT ABS _stack
+ .. ..: ........ 4 OBJECT GLOBAL DEFAULT 9 data_obj
+ .. ..: ........ 0 NOTYPE GLOBAL DEFAULT ABS __bss_start__
+ .. ..: ........ 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ .. ..: ........ 0 NOTYPE GLOBAL DEFAULT ABS _end
+ .. ..: 00000000 0 NOTYPE GLOBAL DEFAULT UND app_func2
+ .. ..: ........ 0 NOTYPE GLOBAL DEFAULT ABS __exidx_end
+ .. ..: ........ 0 NOTYPE GLOBAL DEFAULT 9 __data_start
+ .. ..: ........ 0 NOTYPE GLOBAL DEFAULT ABS __end__
+ .. ..: ........ 0 NOTYPE GLOBAL DEFAULT ABS __exidx_start

-- Khem Raj <kraj@mvista.com> MontaVista Software Inc.


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