summaryrefslogtreecommitdiff
path: root/src/cmd/6l/pass.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/6l/pass.c')
-rw-r--r--src/cmd/6l/pass.c1112
1 files changed, 329 insertions, 783 deletions
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
index f86942926..5c4ed00a6 100644
--- a/src/cmd/6l/pass.c
+++ b/src/cmd/6l/pass.c
@@ -28,9 +28,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Code and data passes.
+
#include "l.h"
#include "../ld/lib.h"
+static void xfol(Prog*, Prog**);
+
// see ../../runtime/proc.c:/StackGuard
enum
{
@@ -38,157 +42,6 @@ enum
StackBig = 4096,
};
-void
-dodata(void)
-{
- int i;
- Sym *s;
- Prog *p;
- int32 t, u;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f dodata\n", cputime());
- Bflush(&bso);
- for(p = datap; p != P; p = p->link) {
- curtext = p; // for diag messages
- s = p->from.sym;
- if(p->as == ADYNT || p->as == AINIT)
- s->value = dtype;
- if(s->type == SBSS)
- s->type = SDATA;
- if(s->type != SDATA && s->type != SELFDATA)
- diag("initialize non-data (%d): %s\n%P",
- s->type, s->name, p);
- t = p->from.offset + p->width;
- if(t > s->value)
- diag("initialize bounds (%lld): %s\n%P",
- s->value, s->name, p);
- }
-
- /* allocate elf guys - must be segregated from real data */
- datsize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SELFDATA)
- continue;
- t = rnd(s->value, 8);
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
- elfdatsize = datsize;
-
- /* allocate small guys */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SDATA)
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t == 0 && s->name[0] != '.') {
- diag("%s: no size", s->name);
- t = 1;
- }
- t = rnd(t, 4);
- s->value = t;
- if(t > MINSIZ)
- continue;
- if(t >= 8)
- datsize = rnd(datsize, 8);
- s->size = t;
- s->value = datsize;
- datsize += t;
- s->type = SDATA1;
- }
-
- /* allocate the rest of the data */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SDATA) {
- if(s->type == SDATA1)
- s->type = SDATA;
- continue;
- }
- t = s->value;
- if(t >= 8)
- datsize = rnd(datsize, 8);
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
- if(datsize)
- datsize = rnd(datsize, 8);
-
- if(debug['j']) {
- /*
- * pad data with bss that fits up to next
- * 8k boundary, then push data to 8k
- */
- u = rnd(datsize, 8192);
- u -= datsize;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t > u)
- continue;
- u -= t;
- s->size = t;
- s->value = datsize;
- s->type = SDATA;
- datsize += t;
- }
- datsize += u;
- }
-}
-
-void
-dobss(void)
-{
- int i;
- Sym *s;
- int32 t;
-
- if(dynptrsize > 0) {
- /* dynamic pointer section between data and bss */
- datsize = rnd(datsize, 8);
- }
-
- /* now the bss */
- bsssize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- s->size = t;
- if(t >= 8)
- bsssize = rnd(bsssize, 8);
- s->value = bsssize + dynptrsize + datsize;
- bsssize += t;
- }
-
- xdefine("data", SBSS, 0);
- xdefine("edata", SBSS, datsize);
- xdefine("end", SBSS, dynptrsize + bsssize + datsize);
-
- if(debug['s'])
- xdefine("symdat", SFIXED, 0);
- else
- xdefine("symdat", SFIXED, SYMDATVA);
-}
-
Prog*
brchain(Prog *p)
{
@@ -205,19 +58,61 @@ brchain(Prog *p)
void
follow(void)
{
+ Prog *firstp, *lastp;
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
- firstp = prg();
- lastp = firstp;
- xfol(textp);
- lastp->link = P;
- firstp = firstp->link;
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ firstp = prg();
+ lastp = firstp;
+ xfol(cursym->text, &lastp);
+ lastp->link = nil;
+ cursym->text = firstp->link;
+ }
}
-void
-xfol(Prog *p)
+static int
+nofollow(int a)
+{
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+ case AIRETQ:
+ case AIRETW:
+ case ARETFL:
+ case ARETFQ:
+ case ARETFW:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pushpop(int a)
+{
+ switch(a) {
+ case APUSHL:
+ case APUSHFL:
+ case APUSHQ:
+ case APUSHFQ:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPQ:
+ case APOPFQ:
+ case APOPW:
+ case APOPFW:
+ return 1;
+ }
+ return 0;
+}
+
+static void
+xfol(Prog *p, Prog **last)
{
Prog *q;
int i;
@@ -226,55 +121,31 @@ xfol(Prog *p)
loop:
if(p == P)
return;
- if(p->as == ATEXT)
- curtext = p;
- if(!curtext->from.sym->reachable) {
- p = p->pcond;
- goto loop;
- }
if(p->as == AJMP)
if((q = p->pcond) != P && q->as != ATEXT) {
+ /* mark instruction as done and continue layout at target of jump */
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
- /* copy up to 4 instructions to avoid branch */
+ /*
+ * p goes here, but already used it elsewhere.
+ * copy up to 4 instructions or else branch to other copy.
+ */
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
- if(q == lastp)
+ if(q == *last)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
- case AIRETQ:
- case AIRETW:
- case ARETFL:
- case ARETFQ:
- case ARETFW:
-
- case APUSHL:
- case APUSHFL:
- case APUSHQ:
- case APUSHFQ:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPQ:
- case APOPFQ:
- case APOPW:
- case APOPFW:
- goto brk;
- }
+ if(nofollow(a) || pushpop(a))
+ break; // NOTE(rsc): arm does goto copy
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
@@ -287,8 +158,8 @@ loop:
q = copyp(p);
p = p->link;
q->mark = 1;
- lastp->link = q;
- lastp = q;
+ (*last)->link = q;
+ *last = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
@@ -296,14 +167,13 @@ loop:
p = q->pcond;
q->pcond = q->link;
q->link = p;
- xfol(q->link);
+ xfol(q->link, last);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
- brk:;
q = prg();
q->as = AJMP;
q->line = p->line;
@@ -312,15 +182,22 @@ loop:
q->pcond = p;
p = q;
}
+
+ /* emit p */
p->mark = 1;
- lastp->link = p;
- lastp = p;
+ (*last)->link = p;
+ *last = p;
a = p->as;
- if(a == AJMP || a == ARET || a == AIRETL || a == AIRETQ || a == AIRETW ||
- a == ARETFL || a == ARETFQ || a == ARETFW)
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
return;
- if(p->pcond != P)
- if(a != ACALL) {
+ if(p->pcond != P && a != ACALL) {
+ /*
+ * some kind of conditional branch.
+ * recurse to follow one path.
+ * continue loop on the other.
+ */
q = brchain(p->link);
if(q != P && q->mark)
if(a != ALOOP) {
@@ -328,7 +205,7 @@ loop:
p->link = p->pcond;
p->pcond = q;
}
- xfol(p->link);
+ xfol(p->link, last);
q = brchain(p->pcond);
if(q->mark) {
p->pcond = q;
@@ -376,32 +253,11 @@ relinv(int a)
case AJOC: return AJOS;
}
diag("unknown relation: %s in %s", anames[a], TNAME);
+ errorexit();
return a;
}
void
-doinit(void)
-{
- Sym *s;
- Prog *p;
- int x;
-
- for(p = datap; p != P; p = p->link) {
- x = p->to.type;
- if(x != D_EXTERN && x != D_STATIC)
- continue;
- s = p->to.sym;
- if(s->type == 0 || s->type == SXREF)
- diag("undefined %s initializer of %s",
- s->name, p->from.sym->name);
- p->to.offset += s->value;
- p->to.type = D_CONST;
- if(s->type == SDATA || s->type == SBSS)
- p->to.offset += INITDAT;
- }
-}
-
-void
patch(void)
{
int32 c;
@@ -419,58 +275,58 @@ patch(void)
s = lookup("exit", 0);
vexit = s->value;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
+ for(cursym = textp; cursym != nil; cursym = cursym->next)
+ for(p = cursym->text; p != P; p = p->link) {
+ if(HEADTYPE == 7 || HEADTYPE == 9) {
+ // ELF uses FS instead of GS.
+ if(p->from.type == D_INDIR+D_GS)
+ p->from.type = D_INDIR+D_FS;
+ if(p->to.type == D_INDIR+D_GS)
+ p->to.type = D_INDIR+D_FS;
+ }
if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
s = p->to.sym;
if(s) {
if(debug['c'])
Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- switch(s->type) {
- default:
+ if((s->type&~SSUB) != STEXT) {
/* diag prints TNAME first */
diag("undefined: %s", s->name);
s->type = STEXT;
s->value = vexit;
continue; // avoid more error messages
- case STEXT:
- p->to.offset = s->value;
- break;
- case SUNDEF:
- p->pcond = UP;
- p->to.offset = 0;
- break;
}
+ if(s->text == nil)
+ continue;
p->to.type = D_BRANCH;
+ p->to.offset = s->text->pc;
+ p->pcond = s->text;
+ continue;
}
}
- if(p->to.type != D_BRANCH || p->pcond == UP)
+ if(p->to.type != D_BRANCH)
continue;
c = p->to.offset;
- for(q = firstp; q != P;) {
- if(q->forwd != P)
- if(c >= q->forwd->pc) {
- q = q->forwd;
- continue;
- }
+ for(q = cursym->text; q != P;) {
if(c == q->pc)
break;
- q = q->link;
+ if(q->forwd != P && c >= q->forwd->pc)
+ q = q->forwd;
+ else
+ q = q->link;
}
if(q == P) {
- diag("branch out of range in %s\n%P [%s]",
- TNAME, p, p->to.sym ? p->to.sym->name : "<nil>");
+ diag("branch out of range in %s (%#ux)\n%P [%s]",
+ TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
p->to.type = D_NONE;
}
p->pcond = q;
}
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
+ for(cursym = textp; cursym != nil; cursym = cursym->next)
+ for(p = cursym->text; p != P; p = p->link) {
p->mark = 0; /* initialization for follow */
- if(p->pcond != P && p->pcond != UP) {
+ if(p->pcond != P) {
p->pcond = brloop(p->pcond);
if(p->pcond != P)
if(p->to.type == D_BRANCH)
@@ -479,40 +335,6 @@ patch(void)
}
}
-#define LOG 5
-void
-mkfwd(void)
-{
- Prog *p;
- int i;
- int32 dwn[LOG], cnt[LOG];
- Prog *lst[LOG];
-
- for(i=0; i<LOG; i++) {
- if(i == 0)
- cnt[i] = 1; else
- cnt[i] = LOG * cnt[i-1];
- dwn[i] = 1;
- lst[i] = P;
- }
- i = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- i--;
- if(i < 0)
- i = LOG-1;
- p->forwd = P;
- dwn[i]--;
- if(dwn[i] <= 0) {
- dwn[i] = cnt[i];
- if(lst[i] != P)
- lst[i]->forwd = p;
- lst[i] = p;
- }
- }
-}
-
Prog*
brloop(Prog *p)
{
@@ -553,378 +375,275 @@ dostkoff(void)
{
Prog *p, *q, *q1;
int32 autoffset, deltasp;
- int a, f, curframe, curbecome, maxbecome, pcsize;
+ int a, pcsize;
uint32 moreconst1, moreconst2, i;
for(i=0; i<nelem(morename); i++) {
symmorestack[i] = lookup(morename[i], 0);
- pmorestack[i] = P;
- }
-
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- for(i=0; i<nelem(morename); i++) {
- if(p->from.sym == symmorestack[i]) {
- pmorestack[i] = p;
- break;
- }
- }
- }
- }
-
- for(i=0; i<nelem(morename); i++) {
- if(pmorestack[i] == P)
- diag("morestack trampoline not defined");
- }
-
- curframe = 0;
- curbecome = 0;
- maxbecome = 0;
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
-
- /* find out how much arg space is used in this TEXT */
- if(p->to.type == (D_INDIR+D_SP))
- if(p->to.offset > curframe)
- curframe = p->to.offset;
-
- switch(p->as) {
- case ATEXT:
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
- curframe = 0;
- curbecome = 0;
-
- curtext = p;
- break;
-
- case ARET:
- /* special form of RET is BECOME */
- if(p->from.type == D_CONST)
- if(p->from.offset > curbecome)
- curbecome = p->from.offset;
- break;
- }
- }
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
-
- if(debug['b'])
- print("max become = %d\n", maxbecome);
- xdefine("ALEFbecome", STEXT, maxbecome);
-
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
- switch(p->as) {
- case ATEXT:
- curtext = p;
- break;
- case ACALL:
- if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
- f = maxbecome - curtext->from.sym->frame;
- if(f <= 0)
- break;
- /* calling a become or calling a variable */
- if(p->to.sym == S || p->to.sym->become) {
- curtext->to.offset += f;
- if(debug['b']) {
- curp = p;
- print("%D calling %D increase %d\n",
- &curtext->from, &p->to, f);
- }
- }
- }
- break;
- }
+ if(symmorestack[i]->type != STEXT)
+ diag("morestack trampoline not defined - %s", morename[i]);
+ pmorestack[i] = symmorestack[i]->text;
}
autoffset = 0;
deltasp = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
- parsetextconst(p->to.offset);
- autoffset = textstksiz;
- if(autoffset < 0)
- autoffset = 0;
-
- q = P;
- q1 = P;
- if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
- diag("nosplit func likely to overflow stack");
-
- if(!(p->from.scale & NOSPLIT)) {
- if(debug['K']) {
- // 6l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_INDIR+D_R15;
- p->from.offset = 8;
- p->to.type = D_SP;
-
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
- }
-
- if(autoffset < StackBig) { // do we need to call morestack?
- if(autoffset <= StackSmall) {
- // small stack
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_R15;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else {
- // large stack
- p = appendp(p);
- p->as = ALEAQ;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(autoffset-StackSmall);
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_R15;
- }
+ p = cursym->text;
+ parsetextconst(p->to.offset);
+ autoffset = textstksiz;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ q = P;
+ q1 = P;
+ if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
+ diag("nosplit func likely to overflow stack");
+
+ if(!(p->from.scale & NOSPLIT)) {
+ p = appendp(p); // load g into CX
+ p->as = AMOVQ;
+ if(HEADTYPE == 7 || HEADTYPE == 9) // ELF uses FS
+ p->from.type = D_INDIR+D_FS;
+ else
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = tlsoffset+0;
+ p->to.type = D_CX;
+
+ if(debug['K']) {
+ // 6l -K means check not only for stack
+ // overflow but stack underflow.
+ // On underflow, INT 3 (breakpoint).
+ // Underflow itself is rare but this also
+ // catches out-of-sync stack guard info
- // common
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q = p;
- }
+ p = appendp(p);
+ p->as = ACMPQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 8;
+ p->to.type = D_SP;
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
- moreconst1 = 0;
- if(autoffset+160 > 4096)
- moreconst1 = (autoffset+160) & ~7LL;
- moreconst2 = textarg;
+ p = appendp(p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q1 = p;
- // 4 varieties varieties (const1==0 cross const2==0)
- // and 6 subvarieties of (const1==0 and const2!=0)
p = appendp(p);
- if(moreconst1 == 0 && moreconst2 == 0) {
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[0];
- p->to.sym = symmorestack[0];
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else
- if(moreconst1 != 0 && moreconst2 == 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst1;
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[1];
- p->to.sym = symmorestack[1];
- } else
- if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
- i = moreconst2/8 + 3;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[i];
- p->to.sym = symmorestack[i];
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else
- if(moreconst1 == 0 && moreconst2 != 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst2;
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ p = appendp(p);
+ p->as = ANOP;
+ q1->pcond = p;
+ q1 = P;
+ }
+ if(autoffset < StackBig) { // do we need to call morestack?
+ if(autoffset <= StackSmall) {
+ // small stack
p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[2];
- p->to.sym = symmorestack[2];
+ p->as = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
} else {
- p->as = AMOVQ;
- p->from.type = D_CONST;
- p->from.offset = (uint64)moreconst2 << 32;
- p->from.offset |= moreconst1;
+ // large stack
+ p = appendp(p);
+ p->as = ALEAQ;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = -(autoffset-StackSmall);
p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[3];
- p->to.sym = symmorestack[3];
+ p->as = ACMPQ;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
}
- }
-
- if(q != P)
- q->pcond = p->link;
- if(autoffset) {
+ // common
p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- if(q != P)
- q->pcond = p;
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q = p;
}
- deltasp = autoffset;
- if(debug['K'] > 1 && autoffset) {
- // 6l -KK means double-check for stack overflow
- // even after calling morestack and even if the
- // function is marked as nosplit.
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_R15;
- p->from.offset = 0;
- p->to.type = D_BX;
+ /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
+ moreconst1 = 0;
+ if(autoffset+160+textarg > 4096)
+ moreconst1 = (autoffset+160) & ~7LL;
+ moreconst2 = textarg;
- p = appendp(p);
- p->as = ASUBQ;
+ // 4 varieties varieties (const1==0 cross const2==0)
+ // and 6 subvarieties of (const1==0 and const2!=0)
+ p = appendp(p);
+ if(moreconst1 == 0 && moreconst2 == 0) {
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[0];
+ p->to.sym = symmorestack[0];
+ } else
+ if(moreconst1 != 0 && moreconst2 == 0) {
+ p->as = AMOVL;
p->from.type = D_CONST;
- p->from.offset = StackSmall+32;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_BX;
+ p->from.offset = moreconst1;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = AJHI;
+ p->as = ACALL;
p->to.type = D_BRANCH;
- q1 = p;
+ p->pcond = pmorestack[1];
+ p->to.sym = symmorestack[1];
+ } else
+ if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
+ i = moreconst2/8 + 3;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[i];
+ p->to.sym = symmorestack[i];
+ } else
+ if(moreconst1 == 0 && moreconst2 != 0) {
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = moreconst2;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = AINT;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[2];
+ p->to.sym = symmorestack[2];
+ } else {
+ p->as = AMOVQ;
p->from.type = D_CONST;
- p->from.offset = 3;
+ p->from.offset = (uint64)moreconst2 << 32;
+ p->from.offset |= moreconst1;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- q1 = P;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[3];
+ p->to.sym = symmorestack[3];
}
}
- pcsize = p->mode/8;
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + pcsize;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + pcsize;
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- continue;
- case APUSHQ:
- case APUSHFQ:
- deltasp += 8;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- continue;
- case APOPQ:
- case APOPFQ:
- deltasp -= 8;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- continue;
- case ARET:
- break;
- }
-
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
- if(p->from.type == D_CONST)
- goto become;
+ if(q != P)
+ q->pcond = p->link;
if(autoffset) {
+ p = appendp(p);
p->as = AADJSP;
p->from.type = D_CONST;
- p->from.offset = -autoffset;
+ p->from.offset = autoffset;
+ p->spadj = autoffset;
+ if(q != P)
+ q->pcond = p;
+ }
+ deltasp = autoffset;
+ if(debug['K'] > 1 && autoffset) {
+ // 6l -KK means double-check for stack overflow
+ // even after calling morestack and even if the
+ // function is marked as nosplit.
p = appendp(p);
- p->as = ARET;
- }
- continue;
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_BX;
- become:
- q = p;
- p = appendp(p);
- p->as = AJMP;
- p->to = q->to;
- p->pcond = q->pcond;
+ p = appendp(p);
+ p->as = ASUBQ;
+ p->from.type = D_CONST;
+ p->from.offset = StackSmall+32;
+ p->to.type = D_BX;
- q->as = AADJSP;
- q->from = zprg.from;
- q->from.type = D_CONST;
- q->from.offset = -autoffset;
- q->to = zprg.to;
- continue;
+ p = appendp(p);
+ p->as = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_BX;
+
+ p = appendp(p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ q1 = p;
+
+ p = appendp(p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(p);
+ p->as = ANOP;
+ q1->pcond = p;
+ q1 = P;
+ }
+
+ for(; p != P; p = p->link) {
+ pcsize = p->mode/8;
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + pcsize;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + pcsize;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ p->spadj = 4;
+ continue;
+ case APUSHQ:
+ case APUSHFQ:
+ deltasp += 8;
+ p->spadj = 8;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ p->spadj = 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ p->spadj = -4;
+ continue;
+ case APOPQ:
+ case APOPFQ:
+ deltasp -= 8;
+ p->spadj = -8;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ p->spadj = -2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ diag("unbalanced PUSH/POP");
+
+ if(autoffset) {
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ p = appendp(p);
+ p->as = ARET;
+ }
+ }
}
}
@@ -975,180 +694,7 @@ undef(void)
Sym *s;
for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
+ for(s = hash[i]; s != S; s = s->hash)
if(s->type == SXREF)
diag("%s: not defined", s->name);
}
-
-void
-import(void)
-{
- int i;
- Sym *s;
-
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
- if(s->value != 0)
- diag("value != 0 on SXREF");
- undefsym(s);
- Bprint(&bso, "IMPORT: %s sig=%lux v=%lld\n", s->name, s->sig, s->value);
- if(debug['S'])
- s->sig = 0;
- }
-}
-
-void
-ckoff(Sym *s, int32 v)
-{
- if(v < 0 || v >= 1<<Roffset)
- diag("relocation offset %ld for %s out of range", v, s->name);
-}
-
-Prog*
-newdata(Sym *s, int o, int w, int t)
-{
- Prog *p;
-
- p = prg();
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- p->as = ADATA;
- p->width = w;
- p->from.scale = w;
- p->from.type = t;
- p->from.sym = s;
- p->from.offset = o;
- p->to.type = D_CONST;
- p->dlink = s->data;
- s->data = p;
- return p;
-}
-
-Prog*
-newtext(Prog *p, Sym *s)
-{
- if(p == P) {
- p = prg();
- p->as = ATEXT;
- p->from.sym = s;
- }
- s->type = STEXT;
- s->text = p;
- s->value = pc;
- lastp->link = p;
- lastp = p;
- p->pc = pc++;
- if(textp == P)
- textp = p;
- else
- etextp->pcond = p;
- etextp = p;
- return p;
-}
-
-void
-export(void)
-{
- int i, j, n, off, nb, sv, ne;
- Sym *s, *et, *str, **esyms;
- Prog *p;
- char buf[NSNAME], *t;
-
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF &&
- s->type != SUNDEF &&
- (nexports == 0 || s->subtype == SEXPORT))
- n++;
- esyms = mal(n*sizeof(Sym*));
- ne = n;
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF &&
- s->type != SUNDEF &&
- (nexports == 0 || s->subtype == SEXPORT))
- esyms[n++] = s;
- for(i = 0; i < ne-1; i++)
- for(j = i+1; j < ne; j++)
- if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
- s = esyms[i];
- esyms[i] = esyms[j];
- esyms[j] = s;
- }
-
- nb = 0;
- off = 0;
- et = lookup(EXPTAB, 0);
- if(et->type != 0 && et->type != SXREF)
- diag("%s already defined", EXPTAB);
- et->type = SDATA;
- str = lookup(".string", 0);
- if(str->type == 0)
- str->type = SDATA;
- sv = str->value;
- for(i = 0; i < ne; i++){
- s = esyms[i];
- if(debug['S'])
- s->sig = 0;
- /* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
-
- /* signature */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.offset = s->sig;
-
- /* address */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.sym = s;
-
- /* string */
- t = s->name;
- n = strlen(t)+1;
- for(;;){
- buf[nb++] = *t;
- sv++;
- if(nb >= NSNAME){
- p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, NSNAME);
- nb = 0;
- }
- if(*t++ == 0)
- break;
- }
-
- /* name */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_STATIC;
- p->to.sym = str;
- p->to.offset = sv-n;
- }
-
- if(nb > 0){
- p = newdata(str, sv-nb, nb, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, nb);
- }
-
- for(i = 0; i < 3; i++){
- newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- }
- et->value = off;
- if(sv == 0)
- sv = 1;
- str->value = sv;
- exports = ne;
- free(esyms);
-}