diff options
Diffstat (limited to 'src/cmd/6g/gsubr.c')
-rw-r--r-- | src/cmd/6g/gsubr.c | 98 |
1 files changed, 48 insertions, 50 deletions
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index 55864c34e..7318909bb 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -31,9 +31,11 @@ #include <u.h> #include <libc.h> #include "gg.h" +#include "../../pkg/runtime/funcdata.h" // TODO(rsc): Can make this bigger if we move // the text segment up higher in 6l for all GOOS. +// At the same time, can raise StackBig in ../../pkg/runtime/stack.h. vlong unmappedzero = 4096; void @@ -218,6 +220,16 @@ gtrack(Sym *s) } void +gargsize(vlong size) +{ + Node n1, n2; + + nodconst(&n1, types[TINT32], PCDATA_ArgSize); + nodconst(&n2, types[TINT32], size); + gins(APCDATA, &n1, &n2); +} + +void ggloblsym(Sym *s, int32 width, int dupok, int rodata) { Prog *p; @@ -494,7 +506,7 @@ fp: break; case 2: // offset output arg -fatal("shouldnt be used"); +fatal("shouldn't be used"); n->op = OINDREG; n->val.u.reg = D_SP; n->xoffset += types[tptr]->width; @@ -528,7 +540,7 @@ ginscon(int as, vlong c, Node *n2) nodconst(&n1, types[TINT64], c); - if(as != AMOVQ && (c < -1LL<<31 || c >= 1LL<<31)) { + if(as != AMOVQ && (c < -(1LL<<31) || c >= 1LL<<31)) { // cannot have 64-bit immediokate in ADD, etc. // instead, MOV into register first. regalloc(&ntmp, types[TINT64], N); @@ -550,6 +562,7 @@ ismem(Node *n) { switch(n->op) { case OITAB: + case OSPTR: case OLEN: case OCAP: case OINDREG: @@ -1055,41 +1068,27 @@ gins(int as, Node *f, Node *t) return p; } -// Generate an instruction referencing *n -// to force segv on nil pointer dereference. void -checkref(Node *n, int force) +fixlargeoffset(Node *n) { - Node m; + Node a; - if(!force && isptr[n->type->etype] && n->type->type->width < unmappedzero) + if(n == N) return; - - regalloc(&m, types[TUINTPTR], n); - cgen(n, &m); - m.xoffset = 0; - m.op = OINDREG; - m.type = types[TUINT8]; - gins(ATESTB, nodintconst(0), &m); - regfree(&m); -} - -static void -checkoffset(Addr *a, int canemitcode) -{ - Prog *p; - - if(a->offset < unmappedzero) + if(n->op != OINDREG) return; - if(!canemitcode) - fatal("checkoffset %#llx, cannot emit code", a->offset); - - // cannot rely on unmapped nil page at 0 to catch - // reference with large offset. instead, emit explicit - // test of 0(reg). - p = gins(ATESTB, nodintconst(0), N); - p->to = *a; - p->to.offset = 0; + if(n->val.u.reg == D_SP) // stack offset cannot be large + return; + if(n->xoffset != (int32)n->xoffset) { + // offset too large, add to register instead. + a = *n; + a.op = OREGISTER; + a.type = types[tptr]; + a.xoffset = 0; + cgen_checknil(&a); + ginscon(optoas(OADD, types[tptr]), n->xoffset, &a); + n->xoffset = 0; + } } /* @@ -1149,7 +1148,6 @@ naddr(Node *n, Addr *a, int canemitcode) a->offset = n->xoffset; if(a->offset != (int32)a->offset) yyerror("offset %lld too large for OINDREG", a->offset); - checkoffset(a, canemitcode); break; case OPARAM: @@ -1268,8 +1266,16 @@ naddr(Node *n, Addr *a, int canemitcode) break; // itab(nil) a->etype = tptr; a->width = widthptr; - if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero) - checkoffset(a, canemitcode); + break; + + case OSPTR: + // pointer in a string or slice + naddr(n->left, a, canemitcode); + if(a->type == D_CONST && a->offset == 0) + break; // ptr(nil) + a->etype = simtype[TUINTPTR]; + a->offset += Array_array; + a->width = widthptr; break; case OLEN: @@ -1280,8 +1286,6 @@ naddr(Node *n, Addr *a, int canemitcode) a->etype = simtype[TUINT]; a->offset += Array_nel; a->width = widthint; - if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero) - checkoffset(a, canemitcode); break; case OCAP: @@ -1292,8 +1296,6 @@ naddr(Node *n, Addr *a, int canemitcode) a->etype = simtype[TUINT]; a->offset += Array_cap; a->width = widthint; - if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero) - checkoffset(a, canemitcode); break; // case OADD: @@ -2033,18 +2035,21 @@ odot: n1.xoffset = oary[0]; } else { cgen(nn, reg); + cgen_checknil(reg); n1.xoffset = -(oary[0]+1); } for(i=1; i<o; i++) { if(oary[i] >= 0) - fatal("cant happen"); + fatal("can't happen"); gins(AMOVQ, &n1, reg); + cgen_checknil(reg); n1.xoffset = -(oary[i]+1); } a->type = D_NONE; a->index = D_NONE; + fixlargeoffset(&n1); naddr(&n1, a, 1); goto yes; @@ -2105,16 +2110,6 @@ oindex: o |= OAddable; } - if(!(o & ODynam) && l->type->width >= unmappedzero && l->op == OIND) { - // cannot rely on page protections to - // catch array ptr == 0, so dereference. - n2 = *reg; - n2.xoffset = 0; - n2.op = OINDREG; - n2.type = types[TUINT8]; - gins(ATESTB, nodintconst(0), &n2); - } - // check bounds if(!debug['B'] && !n->bounded) { // check bounds @@ -2216,6 +2211,7 @@ oindex_const: n2 = *reg; n2.op = OINDREG; n2.xoffset = v*w; + fixlargeoffset(&n2); a->type = D_NONE; a->index = D_NONE; naddr(&n2, a, 1); @@ -2228,6 +2224,7 @@ oindex_const: reg->op = OREGISTER; } n1.xoffset += v*w; + fixlargeoffset(&n1); a->type = D_NONE; a->index= D_NONE; naddr(&n1, a, 1); @@ -2263,6 +2260,7 @@ oindex_const_sudo: n2 = *reg; n2.op = OINDREG; n2.xoffset = v*w; + fixlargeoffset(&n2); a->type = D_NONE; a->index = D_NONE; naddr(&n2, a, 1); |