diff options
author | Russ Cox <rsc@golang.org> | 2009-09-21 15:48:22 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-09-21 15:48:22 -0700 |
commit | 1654609f26e9e22b75329cb15c9ad6d834130cc7 (patch) | |
tree | 4efa488bc2d0766e9d369227a3c394bd944d22ae /src | |
parent | 579fc108944f076a00eee920dd88f24adc90c82e (diff) | |
download | golang-1654609f26e9e22b75329cb15c9ad6d834130cc7.tar.gz |
rewrite RET, indirect CALL, indirect JMP for nacl.
can JMP or CALL indirect through a register R
provided the preceding instruction is AND $~31, R.
R=ken
OCL=34863
CL=34867
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/8l/span.c | 69 |
1 files changed, 66 insertions, 3 deletions
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c index 8253ec9b1..184a37d31 100644 --- a/src/cmd/8l/span.c +++ b/src/cmd/8l/span.c @@ -877,6 +877,22 @@ subreg(Prog *p, int from, int to) print("%P\n", p); } +// nacl RET: +// POPL BX +// ANDL BX, $~31 +// JMP BX +uchar naclret[] = { 0x5b, 0x83, 0xe3, ~31, 0xff, 0xe3 }; + +// nacl JMP BX: +// ANDL BX, $~31 +// JMP BX +uchar nacljmpbx[] = { 0x83, 0xe3, ~31, 0xff, 0xe3 }; + +// nacl CALL BX: +// ANDL BX, $~31 +// CALL BX +uchar naclcallbx[] = { 0x83, 0xe3, ~31, 0xff, 0xd3 }; + void doasm(Prog *p) { @@ -936,6 +952,12 @@ found: break; case Zlit: + if(HEADTYPE == 8 && p->as == ARET) { + // native client return. + for(z=0; z<sizeof(naclret); z++) + *andptr++ = naclret[z]; + break; + } for(; op = o->op[z]; z++) *andptr++ = op; break; @@ -967,6 +989,42 @@ found: break; case Zo_m: + if(HEADTYPE == 8) { + Adr a; + + switch(p->as) { + case AJMP: + if(p->to.type < D_AX || p->to.type > D_DI) + diag("indirect jmp must use register in native client"); + // ANDL $~31, REG + *andptr++ = 0x83; + asmand(&p->to, 04); + *andptr++ = ~31; + // JMP REG + *andptr++ = 0xFF; + asmand(&p->to, 04); + return; + + case ACALL: + a = p->to; + // native client indirect call + if(a.type < D_AX || a.type > D_DI) { + // MOVL target into BX + *andptr++ = 0x8b; + asmand(&p->to, reg[D_BX]); + memset(&a, 0, sizeof a); + a.type = D_BX; + } + // ANDL $~31, REG + *andptr++ = 0x83; + asmand(&a, 04); + *andptr++ = ~31; + // CALL REG + *andptr++ = 0xFF; + asmand(&a, 02); + return; + } + } *andptr++ = op; asmand(&p->to, o->op[z+1]); break; @@ -1320,9 +1378,14 @@ asmins(Prog *p) // - end of call (return address) must be on 32-byte boundary if(p->as == ATEXT) p->pc += 31 & -p->pc; - if(p->as == ACALL) - while((p->pc+5)&31) - p->pc++; + if(p->as == ACALL) { + // must end on 32-byte boundary. + // doasm to find out how long the CALL encoding is. + andptr = and; + doasm(p); + npc = p->pc + (andptr - and); + p->pc += 31 & -npc; + } andptr = and; doasm(p); npc = p->pc + (andptr - and); |