ARM stub sizing fix

Alan Modra amodra@gmail.com
Thu Jan 14 23:53:00 GMT 2010


On Thu, Jan 14, 2010 at 02:48:20PM -0500, Daniel Jacobowitz wrote:
> Yes, this is busted.

Easily fixed.  Breaks arm-call test due to different stub ordering,
but I'll leave fixing the testsuite to an ARM maintainer.

	* elf32-arm.c (arm_type_of_stub): Wrap overlong lines.
	(cortex_a8_erratum_scan): Fix uninitialised warning.
	(elf32_arm_stub_name): Add stub_type param.  Encode stub_type in name.
	Update all callers.
	(elf32_arm_get_stub_entry): Add stub_type param.  Update all callers.
	(elf32_arm_final_link_relocate): Call arm_type_of_stub to determine
	stub type, if any.

Index: bfd/elf32-arm.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-arm.c,v
retrieving revision 1.218
diff -u -p -r1.218 elf32-arm.c
--- bfd/elf32-arm.c	28 Dec 2009 18:55:16 -0000	1.218
+++ bfd/elf32-arm.c	14 Jan 2010 23:33:09 -0000
@@ -3075,7 +3075,9 @@ arm_type_of_stub (struct bfd_link_info *
   r_type = ELF32_R_TYPE (rel->r_info);
 
   /* Keep a simpler condition, for the sake of clarity.  */
-  if (globals->splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1)
+  if (globals->splt != NULL
+      && hash != NULL
+      && hash->root.plt.offset != (bfd_vma) -1)
     {
       use_plt = 1;
       /* Note when dealing with PLT entries: the main PLT stub is in
@@ -3181,7 +3183,9 @@ arm_type_of_stub (struct bfd_link_info *
 	    }
 	}
     }
-  else if (r_type == R_ARM_CALL || r_type == R_ARM_JUMP24 || r_type == R_ARM_PLT32)
+  else if (r_type == R_ARM_CALL
+	   || r_type == R_ARM_JUMP24
+	   || r_type == R_ARM_PLT32)
     {
       if (st_type == STT_ARM_TFUNC)
 	{
@@ -3245,31 +3249,34 @@ static char *
 elf32_arm_stub_name (const asection *input_section,
 		     const asection *sym_sec,
 		     const struct elf32_arm_link_hash_entry *hash,
-		     const Elf_Internal_Rela *rel)
+		     const Elf_Internal_Rela *rel,
+		     enum elf32_arm_stub_type stub_type)
 {
   char *stub_name;
   bfd_size_type len;
 
   if (hash)
     {
-      len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1;
+      len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1 + 2 + 1;
       stub_name = (char *) bfd_malloc (len);
       if (stub_name != NULL)
-	sprintf (stub_name, "%08x_%s+%x",
+	sprintf (stub_name, "%08x_%s+%x_%d",
 		 input_section->id & 0xffffffff,
 		 hash->root.root.root.string,
-		 (int) rel->r_addend & 0xffffffff);
+		 (int) rel->r_addend & 0xffffffff,
+		 (int) stub_type);
     }
   else
     {
-      len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1;
+      len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1 + 2 + 1;
       stub_name = (char *) bfd_malloc (len);
       if (stub_name != NULL)
-	sprintf (stub_name, "%08x_%x:%x+%x",
+	sprintf (stub_name, "%08x_%x:%x+%x_%d",
 		 input_section->id & 0xffffffff,
 		 sym_sec->id & 0xffffffff,
 		 (int) ELF32_R_SYM (rel->r_info) & 0xffffffff,
-		 (int) rel->r_addend & 0xffffffff);
+		 (int) rel->r_addend & 0xffffffff,
+		 (int) stub_type);
     }
 
   return stub_name;
@@ -3283,7 +3290,8 @@ elf32_arm_get_stub_entry (const asection
 			  const asection *sym_sec,
 			  struct elf_link_hash_entry *hash,
 			  const Elf_Internal_Rela *rel,
-			  struct elf32_arm_link_hash_table *htab)
+			  struct elf32_arm_link_hash_table *htab,
+			  enum elf32_arm_stub_type stub_type)
 {
   struct elf32_arm_stub_hash_entry *stub_entry;
   struct elf32_arm_link_hash_entry *h = (struct elf32_arm_link_hash_entry *) hash;
@@ -3309,7 +3317,7 @@ elf32_arm_get_stub_entry (const asection
     {
       char *stub_name;
 
-      stub_name = elf32_arm_stub_name (id_sec, sym_sec, h, rel);
+      stub_name = elf32_arm_stub_name (id_sec, sym_sec, h, rel, stub_type);
       if (stub_name == NULL)
 	return NULL;
 
@@ -4022,7 +4030,7 @@ cortex_a8_erratum_scan (bfd *input_bfd,
 		  && last_was_32bit
 		  && ! last_was_branch)
                 {
-                  bfd_signed_vma offset;
+                  bfd_signed_vma offset = 0;
                   bfd_boolean force_target_arm = FALSE;
 		  bfd_boolean force_target_thumb = FALSE;
                   bfd_vma target;
@@ -4512,7 +4520,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
 		      /* Get the name of this stub.  */
 		      stub_name = elf32_arm_stub_name (id_sec, sym_sec, hash,
-						       irela);
+						       irela, stub_type);
 		      if (!stub_name)
 			goto error_ret_free_internal;
 
@@ -7004,7 +7012,6 @@ elf32_arm_final_link_relocate (reloc_how
 	case R_ARM_PC24:	  /* Arm B/BL instruction.  */
 	case R_ARM_PLT32:
 	  {
-	  bfd_signed_vma branch_offset;
 	  struct elf32_arm_stub_hash_entry *stub_entry = NULL;
 
 	  if (r_type == R_ARM_XPC25)
@@ -7040,8 +7047,9 @@ elf32_arm_final_link_relocate (reloc_how
 	      || r_type == R_ARM_JUMP24
 	      || r_type == R_ARM_PLT32)
 	    {
-	      bfd_vma from;
-	      
+	      enum elf32_arm_stub_type stub_type;
+	      struct elf32_arm_link_hash_entry *hash;
+
 	      /* If the call goes through a PLT entry, make sure to
 		 check distance to the right destination address.  */
 	      if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1)
@@ -7055,25 +7063,21 @@ elf32_arm_final_link_relocate (reloc_how
 		  sym_flags = STT_FUNC;
 		}
 
-	      from = (input_section->output_section->vma
-		      + input_section->output_offset
-		      + rel->r_offset);
-	      branch_offset = (bfd_signed_vma)(value - from);
-
-	      if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET
-		  || branch_offset < ARM_MAX_BWD_BRANCH_OFFSET
-		  || ((sym_flags == STT_ARM_TFUNC)
-		      && (((r_type == R_ARM_CALL) && !globals->use_blx)
-			  || (r_type == R_ARM_JUMP24)
-			  || (r_type == R_ARM_PLT32) ))
-		  )
+	      hash = (struct elf32_arm_link_hash_entry *) h;
+	      stub_type = arm_type_of_stub (info, input_section, rel,
+					    sym_flags, hash,
+					    value, sym_sec,
+					    input_bfd, sym_name);
+
+	      if (stub_type != arm_stub_none)
 		{
 		  /* The target is out of reach, so redirect the
 		     branch to the local stub for this function.  */
 
 		  stub_entry = elf32_arm_get_stub_entry (input_section,
 							 sym_sec, h,
-							 rel, globals);
+							 rel, globals,
+							 stub_type);
 		  if (stub_entry != NULL)
 		    value = (stub_entry->stub_offset
 			     + stub_entry->stub_sec->output_offset
@@ -7489,32 +7493,24 @@ elf32_arm_final_link_relocate (reloc_how
 	  {
 	    /* Check if a stub has to be inserted because the destination
 	       is too far.  */
-	    bfd_vma from;
-	    bfd_signed_vma branch_offset;
-	    struct elf32_arm_stub_hash_entry *stub_entry = NULL;
-
-	    from = (input_section->output_section->vma
-		    + input_section->output_offset
-		    + rel->r_offset);
-	    branch_offset = (bfd_signed_vma)(value - from);
-
-	    if ((!thumb2
-		 && (branch_offset > THM_MAX_FWD_BRANCH_OFFSET
-		     || (branch_offset < THM_MAX_BWD_BRANCH_OFFSET)))
-		||
-		(thumb2
-		 && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET
-		     || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET)))
-		|| ((sym_flags != STT_ARM_TFUNC)
-		    && (((r_type == R_ARM_THM_CALL) && !globals->use_blx)
-			|| r_type == R_ARM_THM_JUMP24)))
+	    enum elf32_arm_stub_type stub_type;
+	    struct elf32_arm_stub_hash_entry *stub_entry;
+	    struct elf32_arm_link_hash_entry *hash;
+
+	    hash = (struct elf32_arm_link_hash_entry *) h;
+	    stub_type = arm_type_of_stub (info, input_section, rel,
+					  sym_flags, hash, value, sym_sec,
+					  input_bfd, sym_name);
+
+	    if (stub_type != arm_stub_none)
 	      {
 		/* The target is out of reach or we are changing modes, so
 		   redirect the branch to the local stub for this
 		   function.  */
 		stub_entry = elf32_arm_get_stub_entry (input_section,
 						       sym_sec, h,
-						       rel, globals);
+						       rel, globals,
+						       stub_type);
 		if (stub_entry != NULL)
 		  value = (stub_entry->stub_offset
 			   + stub_entry->stub_sec->output_offset

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list