Skip to content

Commit

Permalink
liblink, cmd/7l: re-enable VCONADDR class, use ADRP/ADD for MOV $addr…
Browse files Browse the repository at this point in the history
…(SB), Rx

This is the first step in fixing golang#66 and make it possible to build PIE
without text relocations (Darwin/ARM64 forbids text relocations.)

Internal linking is fully working (with verifyAsm=false), but external
linking is not.
  • Loading branch information
minux committed Mar 2, 2015
1 parent 117487f commit 23251a5
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 4 deletions.
41 changes: 41 additions & 0 deletions src/cmd/7l/asm.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ elfreloc1(Reloc *r, vlong sectoff)
return -1;
break;

case R_ADDRARM64:
// two relocations: R_AARCH64_ADR_PREL_PG_HI21 and R_AARCH64_ADD_ABS_LO12_NC
VPUT(R_AARCH64_ADR_PREL_PG_HI21 | (uint64)elfsym<<32);
VPUT(r->xadd);
VPUT(sectoff+4);
VPUT(R_AARCH64_ADD_ABS_LO12_NC | (uint64)elfsym<<32);
break;

case R_CALLARM64:
if(r->siz == 4)
VPUT(R_AARCH64_CALL26 | (uint64)elfsym<<32);
Expand Down Expand Up @@ -151,13 +159,23 @@ machoreloc1(Reloc *r, vlong sectoff)
int
archreloc(Reloc *r, LSym *s, vlong *val)
{
vlong t;
uint32 o0, o1;
int i;

USED(s);

if(linkmode == LinkExternal) {
switch (r->type) {
default:
return -1;

case R_ADDRARM64:
r->done = 0;
r->xsym = r->sym;
r->add = 0;
break;

case R_CALLARM64:
r->done = 0;
r->xsym = r->sym;
Expand All @@ -174,6 +192,29 @@ archreloc(Reloc *r, LSym *s, vlong *val)
case R_GOTOFF:
*val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
return 0;
case R_ADDRARM64:
t = symaddr(r->sym) + r->add - ((s->value + r->off) & ~0xfffull);
// it can actually address +/- 4GB, but for simplicity's sake, we will limit
// the range to just +/- 2GB, which should be more than enough.
if(t != (int32)t)
diag("program too large, address relocation distance = %lld", t);
t = (uint32)t;
t |= ((uvlong)((uint32)t) >> 31) << 32; // preserve the sign bit
// the first instruction is always at the lower address, this is endian neutral;
// but note that o0 and o1 should still use the target endian.
o0 = o1 = 0;
for(i = 0; i < 4; i++)
((uchar*)&o0)[inuxi4[i]] = s->p[r->off + i];
for(i = 0; i < 4; i++)
((uchar*)&o1)[inuxi4[i]] = s->p[r->off + 4 + i];
o0 |= (((t >> 12)&3)<<29) | (((t>>12>>2) & 0x7ffff) << 5);
o1 |= (t & 0xfff) << 10;
// when laid out, the instruction order must always be o1, o2.
if (ctxt->arch->endian == BigEndian)
*val = ((vlong)o0 << 32) | o1;
else
*val = ((vlong)o1 << 32) | o0;
return 0;
case R_CALLARM64: // bl XXXXXX or b YYYYYY
*val = (0xfc000000u & (uint32)r->add) | (uint32)((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4);
return 0;
Expand Down
19 changes: 15 additions & 4 deletions src/liblink/asm7.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,9 @@ static Optab optab[] = {
{ AWORD, C_NONE, C_NONE, C_ADDR, 14, 4, 0 },

{ AMOVW, C_VCON, C_NONE, C_REG, 12, 4, 0, LFROM },
{ AMOVW, C_VCONADDR, C_NONE, C_REG, 68, 8, 0 },
{ AMOV, C_VCON, C_NONE, C_REG, 12, 4, 0, LFROM },
{ AMOV, C_VCONADDR, C_NONE, C_REG, 68, 8, 0 },

{ AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
{ AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
Expand Down Expand Up @@ -1299,10 +1301,7 @@ cmp(int a, int b)
return 1;
break;
case C_VCON:
if(b == C_VCONADDR)
return 1;
else
return cmp(C_LCON, b);
return cmp(C_LCON, b);
case C_LACON:
if(b == C_AACON)
return 1;
Expand Down Expand Up @@ -2715,6 +2714,18 @@ if(0 /*debug['P']*/) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type);
o1 |= 3 << 23;
o1 |= (2<<30) | (5<<27) | (((v/8)&0x7f)<<15) | (p->from.offset<<10) | (p->to.reg<<5) | p->from.reg;
break;
case 68: /* movT $vconaddr(SB), reg -> adrp + add + reloc */
if(p->as == AMOVW)
ctxt->diag("invalid load of 32-bit address\n%P", p);
o1 = ADR(1, 0, p->to.reg);
o2 = opirr(ctxt, AADD) | (p->to.reg<<5) | p->to.reg;
rel = addrel(ctxt->cursym);
rel->off = ctxt->pc;
rel->siz = 8;
rel->sym = p->from.sym;
rel->add = p->from.offset;
rel->type = R_ADDRARM64;
break;
case 90:
// This is supposed to be something that stops execution.
// It's not supposed to be reached, ever, but if it is, we'd
Expand Down

0 comments on commit 23251a5

Please sign in to comment.