summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2014-11-25 16:00:25 -0500
committerAustin Clements <austin@google.com>2014-11-25 16:00:25 -0500
commit99c8479cc6b9cac330eecb041e6f13479322c0d2 (patch)
tree87e1cb4dac535b250cea8ab0d2dc2312687c79c5
parent2c23a1ae9d025cc248e4be1cefaf200add12a285 (diff)
downloadgo-99c8479cc6b9cac330eecb041e6f13479322c0d2.tar.gz
[dev.cc] 9l: make R_CALLPOWER like ELF's R_PPC64_REL24
These accomplished the same thing, but R_CALLPOWER expected the whole instruction to be in the addend (and completely overwrote what was in the text section), while R_PPC64_REL24 overwrites only bits 6 through 24 of whatever was in the text section. Make R_CALLPOWER work like R_PPC64_REL24 to ease the implementation of dynamic linking. LGTM=rsc R=rsc CC=golang-codereviews, minux https://codereview.appspot.com/177430043
-rw-r--r--src/cmd/9l/asm.c22
-rw-r--r--src/liblink/asm9.c2
2 files changed, 14 insertions, 10 deletions
diff --git a/src/cmd/9l/asm.c b/src/cmd/9l/asm.c
index b8ca777c3..65a36285d 100644
--- a/src/cmd/9l/asm.c
+++ b/src/cmd/9l/asm.c
@@ -65,14 +65,6 @@ needlib(char *name)
int nelfsym = 1;
-// b is the addresses, a is the I-form branch instruction template, peform
-// addition so that the instruction jumps to address (offset) b.
-static int32
-braddoff(int32 a, int32 b)
-{
- return (((uint32)a) & 0xfc000003U) | (0x03fffffcU & (uint32)((a & 0x3fffffcU) + b));
-}
-
void
adddynrela(LSym *rel, LSym *s, Reloc *r)
{
@@ -160,7 +152,19 @@ archreloc(Reloc *r, LSym *s, vlong *val)
*val = ((vlong)o2 << 32) | o1;
return 0;
case R_CALLPOWER:
- *val = braddoff((uint32)r->add, (int32)(symaddr(r->sym) - (s->value + r->off)));
+ // Bits 6 through 29 = (S + A - P) >> 2
+ if(ctxt->arch->endian == BigEndian)
+ o1 = be32(s->p + r->off);
+ else
+ o1 = le32(s->p + r->off);
+
+ t = symaddr(r->sym) + r->add - (s->value + r->off);
+ if(t & 3)
+ ctxt->diag("relocation for %s is not aligned: %lld", s->name, t);
+ if(t << 6 >> 6 != t)
+ ctxt->diag("relocation for %s is too big: %lld", s->name, t);
+
+ *val = (o1 & 0xfc000003U) | (t & ~0xfc000003U);
return 0;
}
return -1;
diff --git a/src/liblink/asm9.c b/src/liblink/asm9.c
index 3c125b3b0..5a379270d 100644
--- a/src/liblink/asm9.c
+++ b/src/liblink/asm9.c
@@ -1589,7 +1589,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
ctxt->diag("odd branch target address\n%P", p);
v &= ~03;
}
- rel->add = o1 | (v & 0x03FFFFFC);
+ rel->add = v;
rel->type = R_CALLPOWER;
}
break;