This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[7/21] Handle relative branches to absolute addresses
- From: Richard Sandiford <richards at transitive dot com>
- To: binutils at sourceware dot org
- Date: Tue, 10 Mar 2009 14:13:02 +0000
- Subject: [7/21] Handle relative branches to absolute addresses
- References: <g4y6vd7a4x.fsf@richards-desktop.transitives.com>
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}