This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[PATCH] invalid glue section, arm-thumb interwork
- From: Adam Nemet <anemet at Lnxw dot COM>
- To: binutils at sources dot redhat dot com
- Date: 27 May 2002 20:24:40 -0700
- Subject: [PATCH] invalid glue section, arm-thumb interwork
Hi,
The following testcase produces an invalid glue section on
arm-pc-linux-gnu.
$ cat a.c
_start ()
{
b ();
}
$ cat b.c
b ()
{
}
int c () __attribute__ ((section (".init")));
c ()
{
}
$ gcc -O2 -c -mthumb-interwork -mthumb b.c
$ gcc -O2 -c -mthumb-interwork a.c
$ ./ld-new a.o b.o
$ objdump -d a.out
a.out: file format elf32-littlearm
Disassembly of section .init:
00008074 <c>:
8074: 4770 bx lr
Disassembly of section .text:
00008078 <_start>:
8078: e1a0c00d mov ip, sp
807c: e92dd800 stmdb sp!, {fp, ip, lr, pc}
8080: e24cb004 sub fp, ip, #4 ; 0x4
8084: eb000002 bl 8094 <__b_from_arm>
8088: e91b6800 ldmdb fp, {fp, sp, lr}
808c: e12fff1e bx lr
00008090 <b>:
8090: 4770 bx lr
...
00008094 <__b_from_arm>:
...
-------------------
The reason is the following:
1. The bfd that holds the glue section is always the last one to be
processed. See the bfd_elf32_arm_get_bfd_for_interworking() call
in arm_elf_after_open().
2. build_link_order() following the linker script puts .init before
.text. Consequently, b.o is linked before a.o.
3. The stub functions are added in the order of linking of the input
bfds in elf32_arm_final_link_relocate().
Therefore by the time a.o is linked b.o has been already finalized in
the output_bfd. In turn, b.o will not hold a valid __b_from_arm.
My solution moves the decision as to which bfd we will hold the glue
sections, to a later phase.
After we run map_input_to_output_section it is safe to run a
simplified build_link_order(). This function determines the intput
bfd that will be linked last and hence can hold the interworking
sections.
I ran the testsuite for arm-pc-linux-gnu without any failures. I also
tested this patch on arm-elf-lynxos4 which will be contributed in the
near future. I ran a few thumb/interwork applications with
arm/interwork C-runtime on arm-elf-lynxos4 successfully (which used to
fail without the patch).
I've only added the changes to elf32-arm for now. I will try to
reproduce the problem on pe/coff-arm later and given that my solution
is acceptable for ELF I will separately submit another patch for
pe/coff-arm.
My assigment froms are on file with FSF. Please also apply the patch if
accepted.
Adam
ld/ChangeLog:
2002-05-27 Adam Nemet <anemet@lnxw.com>
* emultempl/armelf.em (arm_elf_after_open): Don't determine
bfd_for_interwork, instead add glue sections to each input bfd.
(bfd_for_interwork): New global.
(arm_elf_set_bfd_for_interworking): New function.
(arm_elf_before_allocation): Use it.
bfd/ChangeLog:
2002-05-27 Adam Nemet <anemet@lnxw.com>
* elf32-arm.h (bfd_elf32_arm_get_bfd_for_interworking): Don't add glue
sections only record bfd.
(bfd_elf32_arm_add_glue_sections_to_bfd): New function.
* bfd-in.h (bfd_elf32_arm_add_glue_sections_to_bfd): Declare it.
* bfd-in2.h: Regenerate.
Index: bfd/bfd-in.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in.h,v
retrieving revision 1.45
diff -p -c -r1.45 bfd-in.h
*** bfd/bfd-in.h 12 Apr 2002 23:02:12 -0000 1.45
--- bfd/bfd-in.h 28 May 2002 02:48:47 -0000
*************** extern boolean bfd_elf32_arm_process_bef
*** 803,808 ****
--- 803,811 ----
extern boolean bfd_elf32_arm_get_bfd_for_interworking
PARAMS ((bfd *, struct bfd_link_info *));
+ extern boolean bfd_elf32_arm_add_glue_sections_to_bfd
+ PARAMS ((bfd *, struct bfd_link_info *));
+
/* TI COFF load page support. */
extern void bfd_ticoff_set_section_load_page
PARAMS ((struct sec *, int));
Index: bfd/bfd-in2.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in2.h,v
retrieving revision 1.152
diff -p -c -r1.152 bfd-in2.h
*** bfd/bfd-in2.h 23 May 2002 13:12:44 -0000 1.152
--- bfd/bfd-in2.h 28 May 2002 02:48:47 -0000
*************** extern boolean bfd_elf32_arm_process_bef
*** 809,814 ****
--- 809,817 ----
extern boolean bfd_elf32_arm_get_bfd_for_interworking
PARAMS ((bfd *, struct bfd_link_info *));
+ extern boolean bfd_elf32_arm_add_glue_sections_to_bfd
+ PARAMS ((bfd *, struct bfd_link_info *));
+
/* TI COFF load page support. */
extern void bfd_ticoff_set_section_load_page
PARAMS ((struct sec *, int));
Index: bfd/elf32-arm.h
===================================================================
RCS file: /cvs/src/src/bfd/elf32-arm.h,v
retrieving revision 1.82
diff -p -c -r1.82 elf32-arm.h
*** bfd/elf32-arm.h 23 May 2002 12:37:19 -0000 1.82
--- bfd/elf32-arm.h 28 May 2002 02:48:47 -0000
*************** record_thumb_to_arm_glue (link_info, h)
*** 547,562 ****
return;
}
! /* Select a BFD to be used to hold the sections used by the glue code.
! This function is called from the linker scripts in ld/emultempl/
! {armelf/pe}.em */
boolean
! bfd_elf32_arm_get_bfd_for_interworking (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
- struct elf32_arm_link_hash_table *globals;
flagword flags;
asection *sec;
--- 547,560 ----
return;
}
! /* Add the glue sections to ABFD. This function is called from the
! linker scripts in ld/emultempl/{armelf}.em. */
boolean
! bfd_elf32_arm_add_glue_sections_to_bfd (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
flagword flags;
asection *sec;
*************** bfd_elf32_arm_get_bfd_for_interworking (
*** 565,577 ****
if (info->relocateable)
return true;
- globals = elf32_arm_hash_table (info);
-
- BFD_ASSERT (globals != NULL);
-
- if (globals->bfd_of_glue_owner != NULL)
- return true;
-
sec = bfd_get_section_by_name (abfd, ARM2THUMB_GLUE_SECTION_NAME);
if (sec == NULL)
--- 563,568 ----
*************** bfd_elf32_arm_get_bfd_for_interworking (
*** 608,613 ****
--- 599,629 ----
sec->gc_mark = 1;
}
+
+ return true;
+ }
+
+ /* Select a BFD to be used to hold the sections used by the glue code.
+ This function is called from the linker scripts in ld/emultempl/
+ {armelf/pe}.em */
+ boolean
+ bfd_elf32_arm_get_bfd_for_interworking (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ {
+ struct elf32_arm_link_hash_table *globals;
+
+ /* If we are only performing a partial link do not bother
+ getting a bfd to hold the glue. */
+ if (info->relocateable)
+ return true;
+
+ globals = elf32_arm_hash_table (info);
+
+ BFD_ASSERT (globals != NULL);
+
+ if (globals->bfd_of_glue_owner != NULL)
+ return true;
/* Save the bfd for later use. */
globals->bfd_of_glue_owner = abfd;
Index: ld/emultempl/armelf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/armelf.em,v
retrieving revision 1.25
diff -p -c -r1.25 armelf.em
*** ld/emultempl/armelf.em 11 Apr 2002 16:55:27 -0000 1.25
--- ld/emultempl/armelf.em 28 May 2002 02:48:48 -0000
*************** cat >>e${EMULATION_NAME}.c <<EOF
*** 27,32 ****
--- 27,34 ----
static int no_pipeline_knowledge = 0;
static char *thumb_entry_symbol = NULL;
+ static bfd *bfd_for_interwork;
+
static void
gld${EMULATION_NAME}_before_parse ()
*************** arm_elf_after_open ()
*** 57,65 ****
{
LANG_FOR_EACH_INPUT_STATEMENT (is)
{
! /* The interworking bfd must be the last one to be processed */
! if (!is->next)
! bfd_elf32_arm_get_bfd_for_interworking (is->the_bfd, & link_info);
}
}
--- 59,65 ----
{
LANG_FOR_EACH_INPUT_STATEMENT (is)
{
! bfd_elf32_arm_add_glue_sections_to_bfd (is->the_bfd, & link_info);
}
}
*************** arm_elf_after_open ()
*** 67,80 ****
--- 67,118 ----
gld${EMULATION_NAME}_after_open ();
}
+ static void arm_elf_set_bfd_for_interworking
+ PARAMS ((lang_statement_union_type *));
+
+ static void
+ arm_elf_set_bfd_for_interworking (statement)
+ lang_statement_union_type *statement;
+ {
+ if (statement->header.type == lang_input_section_enum
+ && statement->input_section.ifile->just_syms_flag == false)
+ {
+ asection *i = statement->input_section.section;
+ asection *output_section = i->output_section;
+
+ ASSERT (output_section->owner == output_bfd);
+
+ if ((output_section->flags & SEC_HAS_CONTENTS) != 0
+ && (i->flags & SEC_NEVER_LOAD) == 0
+ && ! i->owner->output_has_begun)
+ {
+ bfd_for_interwork = i->owner;
+ bfd_for_interwork->output_has_begun = true;
+ }
+ }
+ }
static void arm_elf_before_allocation PARAMS ((void));
static void
arm_elf_before_allocation ()
{
+ bfd *tem;
+
/* Call the standard elf routine. */
gld${EMULATION_NAME}_before_allocation ();
+
+ /* The interworking bfd must be the last one in the link. */
+ bfd_for_interwork = NULL;
+ for (tem = link_info.input_bfds; tem != NULL; tem = tem->link_next)
+ tem->output_has_begun = false;
+
+ lang_for_each_statement (arm_elf_set_bfd_for_interworking);
+ ASSERT (bfd_for_interwork != NULL);
+ for (tem = link_info.input_bfds; tem != NULL; tem = tem->link_next)
+ tem->output_has_begun = false;
+
+ bfd_elf32_arm_get_bfd_for_interworking (bfd_for_interwork, &link_info);
/* We should be able to set the size of the interworking stub section */