This is the mail archive of the binutils@sources.redhat.com 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] 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 */
  


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