Never emit R_ARM_PC24 relocations when linking

Daniel Jacobowitz drow@mvista.com
Wed Jan 7 22:16:00 GMT 2004


Right now we have a lot of baggage carried around for the difference between
R_ARM_PLT32 relocations and R_ARM_PC24.  In particular, we emit R_ARM_PC24
relocations for shared libraries when we receive R_ARM_PC24 input
relocations.  This seems like a misfeature; every branch instruction should
either be resolved locally, or go through a PLT stub.

So, as someone (either Philip Blundell or Richard Earnshaw) suggested to me
last year, this patch removes the special handling of R_ARM_PC24
relocations.  At final_link_relocate time, we reference the PLT entry iff
one was created; while plt.refcount can be inaccurate for whether one is
really needed, once we've converted to plt.offset the decision has been
made.  A consequence of this means that pc_count is no longer needed; it is
subsumed by plt.refcount.

Incidentally I remove an incorrect comment - ".long foo - ." will not
produce an R_ARM_PC24 relocation.  The only way to get one is with a branch.

Tested via make check for targets arm-elf and arm-linux, and a complete
rebuild of world.  It took me a couple tries to hammer out the bugs glibc
turned up.  OK?

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2003-01-07  Daniel Jacobowitz  <drow@mvista.com>

	* elf32-arm.h (struct elf32_arm_relocs_copied): Remove pc_count.
	(elf32_arm_copy_indirect_symbol): Don't copy pc_count.
	(elf32_arm_final_link_relocate): Handle PLT32 and PC24 relocs
	identically.  Do not emit PC24 relocations for shared libraries.
	(elf32_arm_gc_sweep_hook): Handle PLT32 and PC24 relocs
	identically.  Don't adjust pc_count.
	(elf32_arm_check_relocs): Handle PLT32 and PC24 relocs identically.
	Set ELF_LINK_HASH_NEEDS_PLT for both.  Don't adjust pc_count; don't
	adjust count for branch relocations.
	(allocate_dynrelocs): Correct typo in call to
	WILL_CALL_FINISH_DYNAMIC_SYMBOL.  Never allocate space for
	PC24 or PLT32 relocs when linking.

2003-01-07  Daniel Jacobowitz  <drow@mvista.com>

	* ld-arm/arm-lib.d, ld-arm/arm-lib.r: Update for R_ARM_PLT32
	changes.

Index: bfd/elf32-arm.h
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/bfd/elf32-arm.h,v
retrieving revision 1.117
diff -u -p -r1.117 elf32-arm.h
--- bfd/elf32-arm.h	27 Nov 2003 18:49:37 -0000	1.117
+++ bfd/elf32-arm.h	6 Jan 2004 15:26:16 -0000
@@ -205,8 +205,6 @@ struct elf32_arm_relocs_copied
     asection * section;
     /* Number of relocs copied in this section.  */
     bfd_size_type count;
-    /* Number of relocs copied in this section.  */
-    bfd_size_type pc_count;
   };
 
 /* Arm ELF linker hash entry.  */
@@ -383,7 +381,6 @@ elf32_arm_copy_indirect_symbol (const st
 	      for (q = edir->relocs_copied; q != NULL; q = q->next)
 		if (q->section == p->section)
 		  {
-		    q->pc_count += p->pc_count;
 		    q->count += p->count;
 		    *pp = p->next;
 		    break;
@@ -1307,21 +1304,41 @@ elf32_arm_final_link_relocate (howto, in
 #ifndef OLD_ARM_ABI
     case R_ARM_XPC25:
 #endif
+    case R_ARM_PLT32:
       /* r_symndx will be zero only for relocs against symbols
 	 from removed linkonce sections, or sections discarded by
 	 a linker script.  */
       if (r_symndx == 0)
 	return bfd_reloc_ok;
 
+      /* Handle relocations which should use the PLT entry.  ABS32/REL32
+	 will use the symbol's value, which may point to a PLT entry, but we
+	 don't need to handle that here.  If we created a PLT entry, all
+	 branches in this object should go to it.  */
+      if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32)
+	  && h != NULL
+	  && h->plt.offset != (bfd_vma) -1)
+	{
+	  BFD_ASSERT (splt != NULL);
+	  BFD_ASSERT (!SYMBOL_CALLS_LOCAL (info, h));
+
+	  value = (splt->output_section->vma
+		   + splt->output_offset
+		   + h->plt.offset);
+	  return _bfd_final_link_relocate (howto, input_bfd, input_section,
+					   contents, rel->r_offset, value,
+					   (bfd_vma) 0);
+	}
+
       /* When generating a shared object, these relocations are copied
 	 into the output file to be resolved at run time.  */
-      if ((info->shared
-	   && (input_section->flags & SEC_ALLOC)
-	   && (h == NULL
-	       || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-	       || h->root.type != bfd_link_hash_undefweak)
-	   && (r_type != R_ARM_PC24
-	       || !SYMBOL_CALLS_LOCAL (info, h))))
+      if (info->shared
+	  && (input_section->flags & SEC_ALLOC)
+	  && (h == NULL
+	      || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+	      || h->root.type != bfd_link_hash_undefweak)
+	  && r_type != R_ARM_PC24
+	  && r_type != R_ARM_PLT32)
 	{
 	  Elf_Internal_Rela outrel;
 	  bfd_byte *loc;
@@ -1364,8 +1381,7 @@ elf32_arm_final_link_relocate (howto, in
 	    memset (&outrel, 0, sizeof outrel);
 	  else if (h != NULL
 		   && h->dynindx != -1
-		   && (r_type == R_ARM_PC24
-		       || !info->shared
+		   && (!info->shared
 		       || !info->symbolic
 		       || (h->elf_link_hash_flags
 			   & ELF_LINK_HASH_DEF_REGULAR) == 0))
@@ -1397,6 +1413,7 @@ elf32_arm_final_link_relocate (howto, in
 	case R_ARM_XPC25:	  /* Arm BLX instruction.  */
 #endif
 	case R_ARM_PC24:	  /* Arm B/BL instruction */
+	case R_ARM_PLT32:
 #ifndef OLD_ARM_ABI
 	  if (r_type == R_ARM_XPC25)
 	    {
@@ -1869,37 +1886,6 @@ elf32_arm_final_link_relocate (howto, in
 				       contents, rel->r_offset, value,
 				       (bfd_vma) 0);
 
-    case R_ARM_PLT32:
-      /* Relocation is to the entry for this symbol in the
-         procedure linkage table.  */
-
-      /* Resolve a PLT32 reloc against a local symbol directly,
-         without using the procedure linkage table.  */
-      if (h == NULL)
-        return _bfd_final_link_relocate (howto, input_bfd, input_section,
-				 contents, rel->r_offset, value,
-				 (bfd_vma) 0);
-
-      if (h->plt.offset == (bfd_vma) -1
-	  || globals->splt == NULL)
-        /* We didn't make a PLT entry for this symbol.  This
-           happens when statically linking PIC code, or when
-           using -Bsymbolic.  */
-	return _bfd_final_link_relocate (howto, input_bfd, input_section,
-					 contents, rel->r_offset, value,
-					 (bfd_vma) 0);
-
-      BFD_ASSERT(splt != NULL);
-      if (splt == NULL)
-        return bfd_reloc_notsupported;
-
-      value = (splt->output_section->vma
-	       + splt->output_offset
-	       + h->plt.offset);
-      return _bfd_final_link_relocate (howto, input_bfd, input_section,
-			       contents, rel->r_offset, value,
-			       (bfd_vma) 0);
-
     case R_ARM_SBREL32:
       return bfd_reloc_notsupported;
 
@@ -2808,6 +2794,7 @@ elf32_arm_gc_sweep_hook (abfd, info, sec
       case R_ARM_ABS32:
       case R_ARM_REL32:
       case R_ARM_PC24:
+      case R_ARM_PLT32:
 	r_symndx = ELF32_R_SYM (rel->r_info);
 	if (r_symndx >= symtab_hdr->sh_info)
 	  {
@@ -2817,31 +2804,24 @@ elf32_arm_gc_sweep_hook (abfd, info, sec
 
 	    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
-	    if (!info->shared && h->plt.refcount > 0)
+	    if (h->plt.refcount > 0)
 	      h->plt.refcount -= 1;
 
-	    eh = (struct elf32_arm_link_hash_entry *) h;
-
-	    for (pp = &eh->relocs_copied; (p = *pp) != NULL; pp = &p->next)
-	      if (p->section == sec)
-		{
-		  if (ELF32_R_TYPE (rel->r_info) == R_ARM_PC24)
-		    p->pc_count -= 1;
-		  p->count -= 1;
-		  if (p->count == 0)
-		    *pp = p->next;
-		  break;
-		}
-	  }
-	break;
+	    if (ELF32_R_TYPE (rel->r_info) == R_ARM_ABS32
+		|| ELF32_R_TYPE (rel->r_info) == R_ARM_REL32)
+	      {
+		eh = (struct elf32_arm_link_hash_entry *) h;
 
-      case R_ARM_PLT32:
-	r_symndx = ELF32_R_SYM (rel->r_info);
-	if (r_symndx >= symtab_hdr->sh_info)
-	  {
-	    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-	    if (h->plt.refcount > 0)
-	      h->plt.refcount -= 1;
+		for (pp = &eh->relocs_copied; (p = *pp) != NULL;
+		     pp = &p->next)
+		if (p->section == sec)
+		  {
+		    p->count -= 1;
+		    if (p->count == 0)
+		      *pp = p->next;
+		    break;
+		  }
+	      }
 	  }
 	break;
 
@@ -2902,23 +2882,6 @@ elf32_arm_check_relocs (abfd, info, sec,
 
       switch (ELF32_R_TYPE (rel->r_info))
         {
-	  case R_ARM_PLT32:
-	    /* This symbol requires a procedure linkage table entry.  We
-               actually build the entry in adjust_dynamic_symbol,
-               because this might be a case of linking PIC code which is
-               never referenced by a dynamic object, in which case we
-               don't need to generate a procedure linkage table entry
-               after all.  */
-
-	    /* If this is a local symbol, we resolve it directly without
-               creating a procedure linkage table entry.  */
-	    if (h == NULL)
-	      continue;
-
-	    h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-	    h->plt.refcount++;
-	    break;
-
 	  case R_ARM_GOT32:
 	    /* This symbol requires a global offset table entry.  */
 	    if (h != NULL)
@@ -2961,7 +2924,8 @@ elf32_arm_check_relocs (abfd, info, sec,
 	  case R_ARM_ABS32:
 	  case R_ARM_REL32:
 	  case R_ARM_PC24:
-	    if (h != NULL && !info->shared)
+	  case R_ARM_PLT32:
+	    if (h != NULL)
 	      {
 		/* If this reloc is in a read-only section, we might
 		   need a copy reloc.  We can't check reliably at this
@@ -2969,10 +2933,15 @@ elf32_arm_check_relocs (abfd, info, sec,
 		   sections have not yet been mapped to output sections.
 		   Tentatively set the flag for now, and correct in
 		   adjust_dynamic_symbol.  */
-		h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
-		
+		if (!info->shared)
+		  h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
+
 		/* We may need a .plt entry if the function this reloc
-		   refers to is in a shared lib.  */
+		   refers to is in a different object.  */
+		if (ELF32_R_TYPE (rel->r_info) == R_ARM_PC24
+		    || ELF32_R_TYPE (rel->r_info) == R_ARM_PLT32)
+		  h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+
 		h->plt.refcount += 1;
 	      }
 
@@ -2990,7 +2959,8 @@ elf32_arm_check_relocs (abfd, info, sec,
                relocs_copied field of the hash table entry.  */
 	    if (info->shared
 		&& (sec->flags & SEC_ALLOC) != 0
-		&& (ELF32_R_TYPE (rel->r_info) != R_ARM_PC24
+		&& ((ELF32_R_TYPE (rel->r_info) != R_ARM_PC24
+		     && ELF32_R_TYPE (rel->r_info) != R_ARM_PLT32)
 		    || (h != NULL
 			&& (! info->symbolic
 			    || (h->elf_link_hash_flags
@@ -3068,12 +3038,11 @@ elf32_arm_check_relocs (abfd, info, sec,
 		    *head = p;
 		    p->section = sec;
 		    p->count = 0;
-		    p->pc_count = 0;
 		  }
 		
-		p->count += 1;
-		if (ELF32_R_TYPE (rel->r_info) == R_ARM_PC24)
-		  p->pc_count += 1;
+		if (ELF32_R_TYPE (rel->r_info) == R_ARM_ABS32
+		    || ELF32_R_TYPE (rel->r_info) == R_ARM_REL32)
+		  p->count += 1;
 	      }
 	    break;
 
@@ -3348,7 +3317,7 @@ allocate_dynrelocs (h, inf)
 	}
 
       if (info->shared
-	  || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h))
+	  || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
 	{
 	  asection *s = htab->splt;
 
@@ -3432,29 +3401,8 @@ allocate_dynrelocs (h, inf)
 
   if (info->shared)
     {
-      /* The only reloc that uses pc_count is R_ARM_PC24, which will
-	 appear on a call or on something like ".long foo - .".  We
-	 want calls to protected symbols to resolve directly to the
-	 function rather than going via the plt.  If people want
-	 function pointer comparisons to work as expected then they
-	 should avoid writing assembly like ".long foo - .".  */
-      if (SYMBOL_CALLS_LOCAL (info, h))
-	{
-	  struct elf32_arm_relocs_copied **pp;
-
-	  for (pp = &eh->relocs_copied; (p = *pp) != NULL; )
-	    {
-	      p->count -= p->pc_count;
-	      p->pc_count = 0;
-	      if (p->count == 0)
-		*pp = p->next;
-	      else
-		pp = &p->next;
-	    }
-	}
-
-      /* Also discard relocs on undefined weak syms with non-default
-	 visibility.  */
+      /* Discard relocs on undefined weak syms with non-default
+         visibility.  */
       if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
 	  && h->root.type == bfd_link_hash_undefweak)
 	eh->relocs_copied = NULL;
Index: ld/testsuite/ld-arm/arm-lib.d
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/ld/testsuite/ld-arm/arm-lib.d,v
retrieving revision 1.1
diff -u -p -r1.1 arm-lib.d
--- ld/testsuite/ld-arm/arm-lib.d	6 Jan 2004 21:47:38 -0000	1.1
+++ ld/testsuite/ld-arm/arm-lib.d	7 Jan 2004 18:27:33 -0000
@@ -4,12 +4,23 @@ 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\]	; .* <lib_func1-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}
- .*:	ebfffffe 	bl	.* <lib_func1\+0x8>
+ .*:	ebfffff9 	bl	.* <lib_func1-0xc>
  .*:	e89d6800 	ldmia	sp, {fp, sp, lr}
  .*:	e12fff1e 	bx	lr
 
Index: ld/testsuite/ld-arm/arm-lib.r
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/ld/testsuite/ld-arm/arm-lib.r,v
retrieving revision 1.1
diff -u -p -r1.1 arm-lib.r
--- ld/testsuite/ld-arm/arm-lib.r	6 Jan 2004 21:47:38 -0000	1.1
+++ ld/testsuite/ld-arm/arm-lib.r	7 Jan 2004 18:27:33 -0000
@@ -3,6 +3,6 @@ tmpdir/arm-lib.so:     file format elf32
 
 DYNAMIC RELOCATION RECORDS
 OFFSET   TYPE              VALUE 
-.* R_ARM_PC24        app_func2
+.* R_ARM_JUMP_SLOT   app_func2
 
 



More information about the Binutils mailing list