diff --git a/src/cmd/9l/asm.c b/src/cmd/9l/asm.c index b8ca777c35c..65a36285d8e 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 3c125b3b0f3..5a379270d19 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;