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]

[7/21] Handle relative branches to absolute addresses


This patch fixes:

   R_RBR:
   A relative branch which may be modified to become an
   absolute branch.  FIXME: We don't implement this,
   although we should for symbols of storage mapping class
   XMC_XO.

This is fairly important when linking against libc.a without garbage
collection; the libc.a object that defines setjmp and longjmp also defines
a function called ukey_setjmp, which in turn has a branch relocation against
an absolute symbol called ukeyset_activate.  With our default text start
address of 0x10000000, ukeyset_activate is out of range of a relative
branch, and we get a relocation-overflow error.

(You'd normally want to use garbage collection on AIX, but we currently
don't allow that for shared libraries.  Later patches fix this.)

I stuck to bfd_link_hash_defined because that's what the current code
uses elsewhere.  A later patch will add weak support.

OK to install?

Richard


bfd/
	* coff-rs6000.c (xcoff_reloc_type_br): Make the branch absolute
	if the target is absolute.  Fix comment typo.
	(xcoff_ppc_relocate_section): Remove FIXME.
	* coff64-rs6000.c (xcoff64_reloc_type_br): Make the branch absolute
	if the target is absolute.

ld/testsuite/
	* ld-powerpc/aix-abs-branch-1.im, ld-powerpc/aix-abs-branch-1.ex,
	ld-powerpc/aix-abs-branch-1.s,
	ld-powerpc/aix-abs-branch-1.dd: New test.
	* ld-powerpc/aix52.exp: Run it.

Index: bfd/coff-rs6000.c
===================================================================
--- bfd/coff-rs6000.c	2009-03-10 13:38:53.000000000 +0000
+++ bfd/coff-rs6000.c	2009-03-10 13:46:00.000000000 +0000
@@ -2947,11 +2947,13 @@ xcoff_reloc_type_br (input_bfd, input_se
      bfd_byte *contents;
 {
   struct xcoff_link_hash_entry *h;
+  bfd_vma section_offset;
 
   if (0 > rel->r_symndx)
     return FALSE;
 
   h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
+  section_offset = rel->r_vaddr - input_section->vma;
 
   /* If we see an R_BR or R_RBR reloc which is jumping to global
      linkage code, and it is followed by an appropriate cror nop
@@ -2962,12 +2964,12 @@ xcoff_reloc_type_br (input_bfd, input_se
      cror.  */
   if (NULL != h
       && bfd_link_hash_defined == h->root.type
-      && rel->r_vaddr - input_section->vma + 8 <= input_section->size)
+      && section_offset + 8 <= input_section->size)
     {
       bfd_byte *pnext;
       unsigned long next;
 
-      pnext = contents + (rel->r_vaddr - input_section->vma) + 4;
+      pnext = contents + section_offset + 4;
       next = bfd_get_32 (input_bfd, pnext);
 
       /* The _ptrgl function is magic.  It is used by the AIX
@@ -2977,12 +2979,12 @@ xcoff_reloc_type_br (input_bfd, input_se
 	  if (next == 0x4def7b82			/* cror 15,15,15 */
 	      || next == 0x4ffffb82			/* cror 31,31,31 */
 	      || next == 0x60000000)			/* ori r0,r0,0 */
-	    bfd_put_32 (input_bfd, 0x80410014, pnext);	/* lwz r1,20(r1) */
+	    bfd_put_32 (input_bfd, 0x80410014, pnext);	/* lwz r2,20(r1) */
 
 	}
       else
 	{
-	  if (next == 0x80410014)			/* lwz r1,20(r1) */
+	  if (next == 0x80410014)			/* lwz r2,20(r1) */
 	    bfd_put_32 (input_bfd, 0x60000000, pnext);	/* ori r0,r0,0 */
 	}
     }
@@ -2998,16 +3000,41 @@ xcoff_reloc_type_br (input_bfd, input_se
       howto->complain_on_overflow = complain_overflow_dont;
     }
 
-  howto->pc_relative = TRUE;
+  /* The original PC-relative relocation is biased by -r_vaddr, so adding
+     the value below will give the absolute target address.  */
+  *relocation = val + addend + rel->r_vaddr;
+
   howto->src_mask &= ~3;
   howto->dst_mask = howto->src_mask;
 
-  /* A PC relative reloc includes the section address.  */
-  addend += input_section->vma;
+  if (h != NULL
+      && h->root.type == bfd_link_hash_defined
+      && bfd_is_abs_section (h->root.u.def.section)
+      && section_offset + 4 <= input_section->size)
+    {
+      bfd_byte *ptr;
+      bfd_vma insn;
 
-  *relocation = val + addend;
-  *relocation -= (input_section->output_section->vma
-		  + input_section->output_offset);
+      /* Turn the relative branch into an absolute one by setting the
+	 AA bit.  */
+      ptr = contents + section_offset;
+      insn = bfd_get_32 (input_bfd, ptr);
+      insn |= 2;
+      bfd_put_32 (input_bfd, insn, ptr);
+
+      /* Make the howto absolute too.  */
+      howto->pc_relative = FALSE;
+      howto->complain_on_overflow = complain_overflow_bitfield;
+    }
+  else
+    {
+      /* Use a PC-relative howto and subtract the instruction's address
+	 from the target address we calculated above.  */
+      howto->pc_relative = TRUE;
+      *relocation -= (input_section->output_section->vma
+		      + input_section->output_offset
+		      + section_offset);
+    }
   return TRUE;
 }
 
@@ -3323,9 +3350,7 @@ xcoff_complain_overflow_unsigned_func (i
 
    R_RBR:
    A relative branch which may be modified to become an
-   absolute branch.  FIXME: We don't implement this,
-   although we should for symbols of storage mapping class
-   XMC_XO.
+   absolute branch.
 
    R_RL:
    The PowerPC AIX ABI describes this as a load which may be
Index: bfd/coff64-rs6000.c
===================================================================
--- bfd/coff64-rs6000.c	2009-03-10 13:43:22.000000000 +0000
+++ bfd/coff64-rs6000.c	2009-03-10 13:46:00.000000000 +0000
@@ -1117,11 +1117,13 @@ xcoff64_reloc_type_br (input_bfd, input_
      bfd_byte *contents;
 {
   struct xcoff_link_hash_entry *h;
+  bfd_vma section_offset;
 
   if (0 > rel->r_symndx)
     return FALSE;
 
   h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
+  section_offset = rel->r_vaddr - input_section->vma;
 
   /* If we see an R_BR or R_RBR reloc which is jumping to global
      linkage code, and it is followed by an appropriate cror nop
@@ -1132,12 +1134,12 @@ xcoff64_reloc_type_br (input_bfd, input_
      cror.  */
   if (NULL != h
       && bfd_link_hash_defined == h->root.type
-      && rel->r_vaddr - input_section->vma + 8 <= input_section->size)
+      && section_offset + 8 <= input_section->size)
     {
       bfd_byte *pnext;
       unsigned long next;
 
-      pnext = contents + (rel->r_vaddr - input_section->vma) + 4;
+      pnext = contents + section_offset + 4;
       next = bfd_get_32 (input_bfd, pnext);
 
       /* The _ptrgl function is magic.  It is used by the AIX compiler to call
@@ -1166,16 +1168,41 @@ xcoff64_reloc_type_br (input_bfd, input_
       howto->complain_on_overflow = complain_overflow_dont;
     }
 
-  howto->pc_relative = TRUE;
+  /* The original PC-relative relocation is biased by -r_vaddr, so adding
+     the value below will give the absolute target address.  */
+  *relocation = val + addend + rel->r_vaddr;
+
   howto->src_mask &= ~3;
   howto->dst_mask = howto->src_mask;
 
-  /* A PC relative reloc includes the section address.  */
-  addend += input_section->vma;
-
-  *relocation = val + addend;
-  *relocation -= (input_section->output_section->vma
-		  + input_section->output_offset);
+  if (h != NULL
+      && h->root.type == bfd_link_hash_defined
+      && bfd_is_abs_section (h->root.u.def.section)
+      && section_offset + 4 <= input_section->size)
+    {
+      bfd_byte *ptr;
+      bfd_vma insn;
+
+      /* Turn the relative branch into an absolute one by setting the
+	 AA bit.  */
+      ptr = contents + section_offset;
+      insn = bfd_get_32 (input_bfd, ptr);
+      insn |= 2;
+      bfd_put_32 (input_bfd, insn, ptr);
+
+      /* Make the howto absolute too.  */
+      howto->pc_relative = FALSE;
+      howto->complain_on_overflow = complain_overflow_bitfield;
+    }
+  else
+    {
+      /* Use a PC-relative howto and subtract the instruction's address
+	 from the target address we calculated above.  */
+      howto->pc_relative = TRUE;
+      *relocation -= (input_section->output_section->vma
+		      + input_section->output_offset
+		      + section_offset);
+    }
   return TRUE;
 }
 
Index: ld/testsuite/ld-powerpc/aix-abs-branch-1.im
===================================================================
--- /dev/null	2009-02-06 09:11:03.343159000 +0000
+++ ld/testsuite/ld-powerpc/aix-abs-branch-1.im	2009-03-10 13:46:00.000000000 +0000
@@ -0,0 +1,1 @@
+bar	0x1450000
Index: ld/testsuite/ld-powerpc/aix-abs-branch-1.ex
===================================================================
--- /dev/null	2009-02-06 09:11:03.343159000 +0000
+++ ld/testsuite/ld-powerpc/aix-abs-branch-1.ex	2009-03-10 13:46:00.000000000 +0000
@@ -0,0 +1,1 @@
+foo
Index: ld/testsuite/ld-powerpc/aix-abs-branch-1.s
===================================================================
--- /dev/null	2009-02-06 09:11:03.343159000 +0000
+++ ld/testsuite/ld-powerpc/aix-abs-branch-1.s	2009-03-10 13:46:00.000000000 +0000
@@ -0,0 +1,14 @@
+	.globl	foo
+	.csect	foo[PR]
+foo:
+	bl	bar - 0x3000
+	lwz	1,80(1)
+	bl	bar + 0x1000
+	.ifeq	size - 32
+	lwz	2,20(1)
+	.else
+	ld	2,40(1)
+	.endif
+	bl	bar + 0x2800
+	nop
+	bl	bar
Index: ld/testsuite/ld-powerpc/aix-abs-branch-1.dd
===================================================================
--- /dev/null	2009-02-06 09:11:03.343159000 +0000
+++ ld/testsuite/ld-powerpc/aix-abs-branch-1.dd	2009-03-10 13:46:00.000000000 +0000
@@ -0,0 +1,14 @@
+
+.*
+
+
+Disassembly of section \.text:
+
+0*10000000 <foo>:
+ *10000000:.*	bla * 144d000 <.*>
+ *10000004:.*	l(wz|) * r1,80\(r1\)
+ *10000008:.*	bla * 1451000 <.*>
+ *1000000c:.*	(oril * r0,r0,0|nop)
+ *10000010:.*	bla * 1452800 <.*>
+ *10000014:.*	(oril * r0,r0,0|nop)
+ *10000018:.*	bla * 1450000 <.*>
Index: ld/testsuite/ld-powerpc/aix52.exp
===================================================================
--- ld/testsuite/ld-powerpc/aix52.exp	2009-03-10 13:43:53.000000000 +0000
+++ ld/testsuite/ld-powerpc/aix52.exp	2009-03-10 13:46:00.000000000 +0000
@@ -65,6 +65,12 @@ proc run_aix_test { size name ldopts aso
 }
 
 set aix52tests {
+    {"Absolute branch test 1"
+     "-shared -bI:aix-abs-branch-1.im -bE:aix-abs-branch-1.ex"
+     "" {aix-abs-branch-1.s}
+     {{objdump {-dR} aix-abs-branch-1.dd}}
+     "aix-abs-branch-1.so"}
+
     {"Relocations against absolute symbols 1"
      "-shared -bI:aix-abs-reloc-1.im -bE:aix-abs-reloc-1.ex"
      {} {aix-abs-reloc-1.s}


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