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: ARM long branch stubs: PLT32 and JUMP24 relocations (PR9743)


Hi all,

Here is an updated patch, to cope with all the recently added patches.

Christophe.


On 06.03.2009 16:55, Christophe LYON wrote:
Hi all,

The attached patch should enable closing PR9743.
This issue has to do with the previously lacking support for long branch stubs towards PLT entries, which has been partially addressed by my previous patch (http://sourceware.org/ml/binutils/2009-02/msg00359.html).


Then, we still lacked support for PLT32 and JUMP24 relocations, which I have added here. I did not change R_ARM_PC24 handling because during my tests I had no occurrence of it and I didn't want to break something without proper testing. I can give a look at it later it needed.

Roughly speaking, the fix consists in moving the handling of these relocations to a common place with the *CALL* ones already handled by the long branch support code.

There is one special case: as these relocs don't apply to 'bl' instructions, we can't convert these branches into branch + mode switch, so this case has to be taken into account when selecting the appropriate stub.

Regarding the testsuite, I had to update:
* arm-call.d: a new padding word is inserted before the stubs, so several addresses had to be updated.
* arm-pic-veneer.d: the stub code is now common with several other cases, so I chose to update this one rather than several others (add ip,ip,pc vs add ip,pc,ip)
* thumb2-b-interwork.d: the stub is no longer in a separate section, and no longer has a xxx_change_to_arm symbol.



Christophe.



2009-04-17  Christophe Lyon  <christophe.lyon@st.com>

	PR9743
	bfd/
	* elf32-arm.c (arm_type_of_stub): Handle R_ARM_THM_JUMP24,
	R_ARM_JUMP24 and R_ARM_PLT32 relocations.
	(elf32_arm_size_stubs): Likewise.
	(record_thumb_to_arm_glue): Deleted unused function.
	(bfd_elf32_arm_process_before_allocation): No longer handle
	R_ARM_THM_JUMP24, R_ARM_JUMP24 and R_ARM_PLT32 relocations here.
	(elf32_arm_final_link_relocate): Handle R_ARM_THM_JUMP24,
	R_ARM_JUMP24 and R_ARM_PLT32 relocations.

	testsuite/
	* ld-arm/arm-call.d: Update expected result.
	* ld-arm/arm-pic-veneer.d: Likewise.
	* ld-arm/thumb2-b-interwork.d: Likewise.
Index: bfd/elf32-arm.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-arm.c,v
retrieving revision 1.187
diff -u -p -r1.187 elf32-arm.c
--- bfd/elf32-arm.c	17 Apr 2009 13:04:40 -0000	1.187
+++ bfd/elf32-arm.c	17 Apr 2009 13:53:36 -0000
@@ -2915,14 +2915,15 @@ arm_type_of_stub (struct bfd_link_info *
 	 places.  */
     }
 
-  if (r_type == R_ARM_THM_CALL)
+  if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24)
     {
       /* Handle cases where:
 	 - this call goes too far (different Thumb/Thumb2 max
            distance)
-	 - it's a Thumb->Arm call and blx is not available. A stub is
-           needed in this case, but only if this call is not through a
-           PLT entry. Indeed, PLT stubs handle mode switching already.
+	 - it's a Thumb->Arm call and blx is not available, or it's a
+           Thumb->Arm branch (not bl). A stub is needed in this case,
+           but only if this call is not through a PLT entry. Indeed,
+           PLT stubs handle mode switching already.
       */
       if ((!thumb2
 	    && (branch_offset > THM_MAX_FWD_BRANCH_OFFSET
@@ -2931,7 +2932,8 @@ arm_type_of_stub (struct bfd_link_info *
 	      && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET
 		  || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET)))
 	  || ((st_type != STT_ARM_TFUNC)
-	      && ((r_type == R_ARM_THM_CALL) && !globals->use_blx)
+	      && (((r_type == R_ARM_THM_CALL) && !globals->use_blx)
+		  || (r_type == R_ARM_THM_JUMP24))
 	      && !use_plt))
 	{
 	  if (st_type == STT_ARM_TFUNC)
@@ -2941,14 +2943,19 @@ arm_type_of_stub (struct bfd_link_info *
 		{
 		  stub_type = (info->shared | globals->pic_veneer)
 		    /* PIC stubs.  */
-		    ? ((globals->use_blx)
-		       /* V5T and above.  */
+		    ? ((globals->use_blx
+			&& (r_type ==R_ARM_THM_CALL))
+		       /* V5T and above. Stub starts with ARM code, so
+			  we must be able to switch mode before
+			  reaching it, which is only possible for 'bl'
+			  (ie R_ARM_THM_CALL relocation).  */
 		       ? arm_stub_long_branch_any_thumb_pic
 		       /* On V4T, use Thumb code only.  */
 		       : arm_stub_long_branch_v4t_thumb_thumb_pic)
 
 		    /* non-PIC stubs.  */
-		    : ((globals->use_blx)
+		    : ((globals->use_blx
+			&& (r_type ==R_ARM_THM_CALL))
 		       /* V5T and above.  */
 		       ? arm_stub_long_branch_any_any
 		       /* V4T.  */
@@ -2978,14 +2985,16 @@ arm_type_of_stub (struct bfd_link_info *
 
 	      stub_type = (info->shared | globals->pic_veneer)
 		/* PIC stubs.  */
-		? ((globals->use_blx)
+		? ((globals->use_blx
+		    && (r_type ==R_ARM_THM_CALL))
 		   /* V5T and above.  */
 		   ? arm_stub_long_branch_any_arm_pic
 		   /* V4T PIC stub.  */
 		   : arm_stub_long_branch_v4t_thumb_arm_pic)
 
 		/* non-PIC stubs.  */
-		: ((globals->use_blx)
+		: ((globals->use_blx
+		    && (r_type ==R_ARM_THM_CALL))
 		   /* V5T and above.  */
 		   ? arm_stub_long_branch_any_any
 		   /* V4T.  */
@@ -2999,7 +3008,7 @@ arm_type_of_stub (struct bfd_link_info *
 	    }
 	}
     }
-  else if (r_type == R_ARM_CALL)
+  else if (r_type == R_ARM_CALL || r_type == R_ARM_JUMP24 || r_type == R_ARM_PLT32)
     {
       if (st_type == STT_ARM_TFUNC)
 	{
@@ -3019,7 +3028,9 @@ arm_type_of_stub (struct bfd_link_info *
 	     the mode change (bit 24 (H) of BLX encoding).  */
 	  if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2)
 	      || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)
-	      || !globals->use_blx)
+	      || ((r_type == R_ARM_CALL) && !globals->use_blx)
+	      || (r_type == R_ARM_JUMP24)
+	      || (r_type == R_ARM_PLT32))
 	    {
 	      stub_type = (info->shared | globals->pic_veneer)
 		/* PIC stubs.  */
@@ -3763,9 +3774,12 @@ elf32_arm_size_stubs (bfd *output_bfd,
 		      goto error_ret_free_local;
 		    }
 
-		  /* Only look for stubs on call instructions.  */
+		  /* Only look for stubs on branch instructions.  */
 		  if ((r_type != (unsigned int) R_ARM_CALL)
-		      && (r_type != (unsigned int) R_ARM_THM_CALL))
+		      && (r_type != (unsigned int) R_ARM_THM_CALL)
+		      && (r_type != (unsigned int) R_ARM_JUMP24)
+		      && (r_type != (unsigned int) R_ARM_THM_JUMP24)
+		      && (r_type != (unsigned int) R_ARM_PLT32))
 		    continue;
 
 		  /* Now determine the call target, its name, value,
@@ -3916,11 +3930,13 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
 		  /* For historical reasons, use the existing names for
 		     ARM-to-Thumb and Thumb-to-ARM stubs.  */
-		  if (r_type == (unsigned int) R_ARM_THM_CALL
-		      && st_type != STT_ARM_TFUNC)
+		  if ( ((r_type == (unsigned int) R_ARM_THM_CALL)
+			|| (r_type == (unsigned int) R_ARM_THM_JUMP24))
+		       && st_type != STT_ARM_TFUNC)
 		    sprintf (stub_entry->output_name, THUMB2ARM_GLUE_ENTRY_NAME,
 			     sym_name);
-		  else if (r_type == (unsigned int) R_ARM_CALL
+		  else if ( ((r_type == (unsigned int) R_ARM_CALL)
+			     || (r_type == (unsigned int) R_ARM_JUMP24))
 			   && st_type == STT_ARM_TFUNC)
 		    sprintf (stub_entry->output_name, ARM2THUMB_GLUE_ENTRY_NAME,
 			     sym_name);
@@ -4255,86 +4271,6 @@ record_arm_to_thumb_glue (struct bfd_lin
   return myh;
 }
 
-static void
-record_thumb_to_arm_glue (struct bfd_link_info *link_info,
-			  struct elf_link_hash_entry *h)
-{
-  const char *name = h->root.root.string;
-  asection *s;
-  char *tmp_name;
-  struct elf_link_hash_entry *myh;
-  struct bfd_link_hash_entry *bh;
-  struct elf32_arm_link_hash_table *hash_table;
-  bfd_vma val;
-
-  hash_table = elf32_arm_hash_table (link_info);
-
-  BFD_ASSERT (hash_table != NULL);
-  BFD_ASSERT (hash_table->bfd_of_glue_owner != NULL);
-
-  s = bfd_get_section_by_name
-    (hash_table->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
-
-  BFD_ASSERT (s != NULL);
-
-  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
-			 + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1);
-
-  BFD_ASSERT (tmp_name);
-
-  sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
-
-  myh = elf_link_hash_lookup
-    (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE);
-
-  if (myh != NULL)
-    {
-      /* We've already seen this guy.  */
-      free (tmp_name);
-      return;
-    }
-
-  /* The only trick here is using hash_table->thumb_glue_size as the value.
-     Even though the section isn't allocated yet, this is where we will be
-     putting it.  The +1 on the value marks that the stub has not been
-     output yet - not that it is a Thumb function.  */
-  bh = NULL;
-  val = hash_table->thumb_glue_size + 1;
-  _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner,
-				    tmp_name, BSF_GLOBAL, s, val,
-				    NULL, TRUE, FALSE, &bh);
-
-  /* If we mark it 'Thumb', the disassembler will do a better job.  */
-  myh = (struct elf_link_hash_entry *) bh;
-  myh->type = ELF_ST_INFO (STB_LOCAL, STT_ARM_TFUNC);
-  myh->forced_local = 1;
-
-  free (tmp_name);
-
-#define CHANGE_TO_ARM "__%s_change_to_arm"
-#define BACK_FROM_ARM "__%s_back_from_arm"
-
-  /* Allocate another symbol to mark where we switch to Arm mode.  */
-  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
-			 + strlen (CHANGE_TO_ARM) + 1);
-
-  BFD_ASSERT (tmp_name);
-
-  sprintf (tmp_name, CHANGE_TO_ARM, name);
-
-  bh = NULL;
-  val = hash_table->thumb_glue_size + 4,
-  _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner,
-				    tmp_name, BSF_LOCAL, s, val,
-				    NULL, TRUE, FALSE, &bh);
-
-  free (tmp_name);
-
-  s->size += THUMB2ARM_GLUE_SIZE;
-  hash_table->thumb_glue_size += THUMB2ARM_GLUE_SIZE;
-}
-
-
 /* Allocate space for ARMv4 BX veneers.  */
 
 static void
@@ -4710,9 +4646,6 @@ bfd_elf32_arm_process_before_allocation 
 
 	  /* These are the only relocation types we care about.  */
 	  if (   r_type != R_ARM_PC24
-	      && r_type != R_ARM_PLT32
-	      && r_type != R_ARM_JUMP24
-	      && r_type != R_ARM_THM_JUMP24
 	      && (r_type != R_ARM_V4BX || globals->fix_v4bx < 2))
 	    continue;
 
@@ -4764,8 +4697,6 @@ bfd_elf32_arm_process_before_allocation 
 	  switch (r_type)
 	    {
 	    case R_ARM_PC24:
-	    case R_ARM_PLT32:
-	    case R_ARM_JUMP24:
 	      /* This one is a call from arm code.  We need to look up
 	         the target of the call.  If it is a thumb target, we
 	         insert glue.  */
@@ -4773,16 +4704,6 @@ bfd_elf32_arm_process_before_allocation 
 		record_arm_to_thumb_glue (link_info, h);
 	      break;
 
-	    case R_ARM_THM_JUMP24:
-	      /* This one is a call from thumb code.  We look
-	         up the target of the call.  If it is not a thumb
-                 target, we insert glue.  */
-	      if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC
-		  && !(globals->use_blx && r_type == R_ARM_THM_CALL)
-		  && h->root.type != bfd_link_hash_undefweak)
-		record_thumb_to_arm_glue (link_info, h);
-	      break;
-
 	    default:
 	      abort ();
 	    }
@@ -6128,7 +6049,9 @@ elf32_arm_final_link_relocate (reloc_how
 	 far away, in which case a long branch stub should be inserted.  */
       if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32
            && r_type != R_ARM_ABS32_NOI && r_type != R_ARM_REL32_NOI
-	   && r_type != R_ARM_CALL)
+	   && r_type != R_ARM_CALL
+	   && r_type != R_ARM_JUMP24
+	   && r_type != R_ARM_PLT32)
 	  && h != NULL
 	  && splt != NULL
 	  && h->plt.offset != (bfd_vma) -1)
@@ -6296,7 +6219,7 @@ elf32_arm_final_link_relocate (reloc_how
 		   input_bfd,
 		   h ? h->root.root.string : "(local)");
 	    }
-	  else if (r_type != R_ARM_CALL)
+	  else if (r_type == R_ARM_PC24)
 	    {
 	      /* Check for Arm calling Thumb function.  */
 	      if (sym_flags == STT_ARM_TFUNC)
@@ -6314,7 +6237,9 @@ elf32_arm_final_link_relocate (reloc_how
 
 	  /* Check if a stub has to be inserted because the
 	     destination is too far or we are changing mode.  */
-	  if (r_type == R_ARM_CALL)
+	  if (   r_type == R_ARM_CALL
+	      || r_type == R_ARM_JUMP24
+	      || r_type == R_ARM_PLT32)
 	    {
 	      /* If the call goes through a PLT entry, make sure to
 		 check distance to the right destination address.  */
@@ -6333,7 +6258,11 @@ elf32_arm_final_link_relocate (reloc_how
 
 	      if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET
 		  || branch_offset < ARM_MAX_BWD_BRANCH_OFFSET
-		  || sym_flags == STT_ARM_TFUNC)
+		  || ((sym_flags == STT_ARM_TFUNC)
+		      && (((r_type == R_ARM_CALL) && !globals->use_blx)
+			  || (r_type == R_ARM_JUMP24)
+			  || (r_type == R_ARM_PLT32) ))
+		  )
 		{
 		  /* The target is out of reach, so redirect the
 		     branch to the local stub for this function.  */
@@ -6399,16 +6328,17 @@ elf32_arm_final_link_relocate (reloc_how
 	      value = (signed_addend & howto->dst_mask)
 		| (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask));
 
-	      /* Set the H bit in the BLX instruction.  */
-	      if (sym_flags == STT_ARM_TFUNC)
-		{
-		  if (addend)
-		    value |= (1 << 24);
-		  else
-		    value &= ~(bfd_vma)(1 << 24);
-		}
 	      if (r_type == R_ARM_CALL)
 		{
+		  /* Set the H bit in the BLX instruction.  */
+		  if (sym_flags == STT_ARM_TFUNC)
+		    {
+		      if (addend)
+			value |= (1 << 24);
+		      else
+			value &= ~(bfd_vma)(1 << 24);
+		    }
+
 		  /* Select the correct instruction (BL or BLX).  */
 		  /* Only if we are not handling a BL to a stub. In this
 		     case, mode switching is performed by the stub.  */
@@ -6652,7 +6582,8 @@ elf32_arm_final_link_relocate (reloc_how
 		    /* Convert BL to BLX.  */
 		    lower_insn = (lower_insn & ~0x1000) | 0x0800;
 		  }
-		else if (r_type != R_ARM_THM_CALL)
+		else if ((   r_type != R_ARM_THM_CALL)
+			 && (r_type != R_ARM_THM_JUMP24))
 		  {
 		    if (elf32_thumb_to_arm_stub
 			(info, sym_name, input_bfd, output_bfd, input_section,
@@ -6689,7 +6620,7 @@ elf32_arm_final_link_relocate (reloc_how
 	    *unresolved_reloc_p = FALSE;
 	  }
 
-	if (r_type == R_ARM_THM_CALL)
+	if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24)
 	  {
 	    /* Check if a stub has to be inserted because the destination
 	       is too far.  */
@@ -6709,7 +6640,9 @@ elf32_arm_final_link_relocate (reloc_how
 		(thumb2
 		 && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET
 		     || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET)))
-		|| ((sym_flags != STT_ARM_TFUNC) && !globals->use_blx))
+		|| ((sym_flags != STT_ARM_TFUNC)
+		    && (((r_type == R_ARM_THM_CALL) && !globals->use_blx)
+			|| r_type == R_ARM_THM_JUMP24)))
 	      {
 		/* The target is out of reach or we are changing modes, so
 		   redirect the branch to the local stub for this
@@ -6723,7 +6656,7 @@ elf32_arm_final_link_relocate (reloc_how
 			   + stub_entry->stub_sec->output_section->vma);
 
 		/* If this call becomes a call to Arm, force BLX.  */
-		if (globals->use_blx)
+		if (globals->use_blx && (r_type == R_ARM_THM_CALL))
 		  {
 		    if ((stub_entry
 			 && !arm_stub_is_thumb (stub_entry->stub_type))
Index: ld/testsuite/ld-arm/arm-call.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-arm/arm-call.d,v
retrieving revision 1.3
diff -u -p -r1.3 arm-call.d
--- ld/testsuite/ld-arm/arm-call.d	22 May 2007 17:17:53 -0000	1.3
+++ ld/testsuite/ld-arm/arm-call.d	17 Apr 2009 13:53:41 -0000
@@ -10,10 +10,10 @@ Disassembly of section .text:
     800c:	fb00000d 	blx	804a <t5>
     8010:	fa00000a 	blx	8040 <t1>
     8014:	fb000009 	blx	8042 <t2>
-    8018:	ea00000f 	b	805c <__t1_from_arm>
-    801c:	ea000010 	b	8064 <__t2_from_arm>
-    8020:	1b00000d 	blne	805c <__t1_from_arm>
-    8024:	1b00000e 	blne	8064 <__t2_from_arm>
+    8018:	ea000010 	b	8060 <__t1_from_arm>
+    801c:	ea000011 	b	8068 <__t2_from_arm>
+    8020:	1b00000e 	blne	8060 <__t1_from_arm>
+    8024:	1b00000f 	blne	8068 <__t2_from_arm>
     8028:	1b000003 	blne	803c <arm>
     802c:	eb000002 	bl	803c <arm>
     8030:	faffffff 	blx	8034 <thumblocal>
@@ -46,11 +46,13 @@ Disassembly of section .text:
     8050:	f7ff fff1 	bl	8036 <t3>
     8054:	f7ff efd4 	blx	8000 <_start>
     8058:	f7ff efd2 	blx	8000 <_start>
+    805c:	0000      	lsls	r0, r0, #0
+	...
 
-0000805c <__t1_from_arm>:
-    805c:	e51ff004 	ldr	pc, \[pc, #-4\]	; 8060 <__t1_from_arm\+0x4>
-    8060:	00008041 	.word	0x00008041
-
-00008064 <__t2_from_arm>:
-    8064:	e51ff004 	ldr	pc, \[pc, #-4\]	; 8068 <__t2_from_arm\+0x4>
-    8068:	00008043 	.word	0x00008043
+00008060 <__t1_from_arm>:
+    8060:	e51ff004 	ldr	pc, \[pc, #-4\]	; 8064 <__t1_from_arm\+0x4>
+    8064:	00008041 	.word	0x00008041
+
+00008068 <__t2_from_arm>:
+    8068:	e51ff004 	ldr	pc, \[pc, #-4\]	; 806c <__t2_from_arm\+0x4>
+    806c:	00008043 	.word	0x00008043
Index: ld/testsuite/ld-arm/arm-pic-veneer.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-arm/arm-pic-veneer.d,v
retrieving revision 1.2
diff -u -p -r1.2 arm-pic-veneer.d
--- ld/testsuite/ld-arm/arm-pic-veneer.d	22 May 2007 17:17:53 -0000	1.2
+++ ld/testsuite/ld-arm/arm-pic-veneer.d	17 Apr 2009 13:53:41 -0000
@@ -12,6 +12,6 @@ Disassembly of section .text:
 
 00008008 <__foo_from_arm>:
     8008:	e59fc004 	ldr	ip, \[pc, #4\]	; 8014 <__foo_from_arm\+0xc>
-    800c:	e08cc00f 	add	ip, ip, pc
+    800c:	e08fc00c 	add	ip, pc, ip
     8010:	e12fff1c 	bx	ip
     8014:	fffffff1 	.word	0xfffffff1
Index: ld/testsuite/ld-arm/thumb2-b-interwork.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-arm/thumb2-b-interwork.d,v
retrieving revision 1.1
diff -u -p -r1.1 thumb2-b-interwork.d
--- ld/testsuite/ld-arm/thumb2-b-interwork.d	8 Mar 2008 14:58:14 -0000	1.1
+++ ld/testsuite/ld-arm/thumb2-b-interwork.d	17 Apr 2009 13:53:41 -0000
@@ -8,12 +8,9 @@ Disassembly of section .text:
 
 00008004 <bar>:
     8004:	e12fff1e 	bx	lr
-Disassembly of section .glue_7t:
 
 00008008 <__bar_from_thumb>:
     8008:	4778      	bx	pc
     800a:	46c0      	nop			\(mov r8, r8\)
-
-0000800c <__bar_change_to_arm>:
     800c:	eafffffc 	b	8004 <bar>
 

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