/* allocate the rest of the data */
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SDATA) {
if(s->type == SDATA1)
s->type = SDATA;
continue;
}
t = s->value;
s->value = datsize;
datsize += t;
}
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->type != SBSS)
continue;
t = s->value;
if(t > u)
continue;
u -= t;
s->value = datsize;
s->type = SDATA;
datsize += t;
}
datsize += u;
}
/* now the bss */
bsssize = 0;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SBSS)
continue;
t = s->value;
s->value = bsssize + datsize;
bsssize += t;
}
xdefine("bdata", SDATA, 0L);
xdefine("edata", SBSS, datsize);
xdefine("end", SBSS, bsssize + datsize);
/* etext is defined in span.c */
}
Prog*
brchain(Prog *p)
{
int i;
for(i=0; i<20; i++) {
if(p == P || p->as != AJMP)
return p;
p = p->pcond;
}
return P;
}
loop:
if(p == P)
return;
if(p->as == ATEXT)
curtext = p;
if(p->as == AJMP)
if((q = p->pcond) != P) {
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
/* copy up to 4 instructions to avoid branch */
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
if(q == lastp)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
switch(a) {
case AJMP:
case ARET:
case AIRETL:
case APUSHL:
case APUSHFL:
case APUSHW:
case APUSHFW:
case APOPL:
case APOPFL:
case APOPW:
case APOPFW:
goto brk;
}
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
continue;
for(;;) {
if(p->as == ANOP) {
p = p->link;
continue;
}
q = copyp(p);
p = p->link;
q->mark = 1;
lastp->link = q;
lastp = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
switch(a) {
case AJEQ: return AJNE;
case AJNE: return AJEQ;
case AJLE: return AJGT;
case AJLS: return AJHI;
case AJLT: return AJGE;
case AJMI: return AJPL;
case AJGE: return AJLT;
case AJPL: return AJMI;
case AJGT: return AJLE;
case AJHI: return AJLS;
case AJCS: return AJCC;
case AJCC: return AJCS;
case AJPS: return AJPC;
case AJPC: return AJPS;
case AJOS: return AJOC;
case AJOC: return AJOS;
}
diag("unknown relation: %s in %s", anames[a], TNAME);
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)
{
long c;
Prog *p, *q;
Sym *s;
long vexit;
if(debug['v'])
Bprint(&bso, "%5.2f mkfwd\n", cputime());
Bflush(&bso);
mkfwd();
if(debug['v'])
Bprint(&bso, "%5.2f patch\n", cputime());
Bflush(&bso);
s = lookup("exit", 0);
vexit = s->value;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
if(p->as == ACALL || p->as == ARET) {
s = p->to.sym;
if(s) {
if(debug['c'])
Bprint(&bso, "%s calls %s\n", TNAME, s->name);
switch(s->type) {
default:
/* diag prints TNAME first */
diag("undefined: %s", s->name);
s->type = STEXT;
s->value = vexit;
break; /* or fall through to set offset? */
case STEXT:
p->to.offset = s->value;
break;
case SUNDEF:
p->pcond = UP;
p->to.offset = 0;
break;
}
p->to.type = D_BRANCH;
}
}
if(p->to.type != D_BRANCH || p->pcond == UP)
continue;
c = p->to.offset;
for(q = firstp; q != P;) {
if(q->forwd != P)
if(c >= q->forwd->pc) {
q = q->forwd;
continue;
}
if(c == q->pc)
break;
q = q->link;
}
if(q == P) {
diag("branch out of range in %s\n%P", TNAME, p);
p->to.type = D_NONE;
}
p->pcond = q;
}
switch(p->as) {
default:
continue;
case APUSHL:
case APUSHFL:
deltasp += 4;
continue;
case APUSHW:
case APUSHFW:
deltasp += 2;
continue;
case APOPL:
case APOPFL:
deltasp -= 4;
continue;
case APOPW:
case APOPFW:
deltasp -= 2;
continue;
case ARET:
break;
}