]> Cypherpunks repositories - gostls13.git/commitdiff
rewrite RET, indirect CALL, indirect JMP for nacl.
authorRuss Cox <rsc@golang.org>
Mon, 21 Sep 2009 22:48:22 +0000 (15:48 -0700)
committerRuss Cox <rsc@golang.org>
Mon, 21 Sep 2009 22:48:22 +0000 (15:48 -0700)
can JMP or CALL indirect through a register R
provided the preceding instruction is AND $~31, R.

R=ken
OCL=34863
CL=34867

src/cmd/8l/span.c

index 8253ec9b16ad3397d1b0da32b06f1582c37bc1d7..184a37d3166e73dff7992d2dc9ad90fff2fd3b6f 100644 (file)
@@ -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);