diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2019-04-08 14:05:27 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2019-04-08 14:05:27 +0200 |
commit | d8d4802f80b40bc9a43031e3d6484aa237e7d444 (patch) | |
tree | 7714690d2d47f2aedf4ad60ad9ad0e6d88db2a1b /sys/src/cmd/7l/pass.c | |
parent | 394d095ee0a9e50242b88a783af6bb777cfb3e01 (diff) |
7l: add arm64 linker (initial sync)
Diffstat (limited to 'sys/src/cmd/7l/pass.c')
-rw-r--r-- | sys/src/cmd/7l/pass.c | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/sys/src/cmd/7l/pass.c b/sys/src/cmd/7l/pass.c new file mode 100644 index 000000000..ad3d9a439 --- /dev/null +++ b/sys/src/cmd/7l/pass.c @@ -0,0 +1,448 @@ +#include "l.h" + +vlong +atolwhex(char *s) +{ + vlong n; + int f; + + n = 0; + f = 0; + while(*s == ' ' || *s == '\t') + s++; + if(*s == '-' || *s == '+') { + if(*s++ == '-') + f = 1; + while(*s == ' ' || *s == '\t') + s++; + } + if(s[0]=='0' && s[1]){ + if(s[1]=='x' || s[1]=='X'){ + s += 2; + for(;;){ + if(*s >= '0' && *s <= '9') + n = n*16 + *s++ - '0'; + else if(*s >= 'a' && *s <= 'f') + n = n*16 + *s++ - 'a' + 10; + else if(*s >= 'A' && *s <= 'F') + n = n*16 + *s++ - 'A' + 10; + else + break; + } + } else + while(*s >= '0' && *s <= '7') + n = n*8 + *s++ - '0'; + } else + while(*s >= '0' && *s <= '9') + n = n*10 + *s++ - '0'; + if(f) + n = -n; + return n; +} + +vlong +rnd(vlong v, long r) +{ + long c; + + if(r <= 0) + return v; + v += r - 1; + c = v % r; + if(c < 0) + c += r; + v -= c; + return v; +} + +void +dodata(void) +{ + int i, t; + Sym *s; + Prog *p; + long orig, v; + + if(debug['v']) + Bprint(&bso, "%5.2f dodata\n", cputime()); + Bflush(&bso); + for(p = datap; p != P; p = p->link) { + 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) + diag("initialize non-data (%d): %s\n%P", + s->type, s->name, p); + v = p->from.offset + p->reg; + if(v > s->value) + diag("initialize bounds (%lld): %s\n%P", + (vlong)s->value, s->name, p); + } + + if(debug['t']) { + /* + * pull out string constants + */ + for(p = datap; p != P; p = p->link) { + s = p->from.sym; + if(p->to.type == D_SCONST) + s->type = SSTRING; + } + } + + /* + * pass 1 + * assign 'small' variables to data segment + * (rationale is that data segment is more easily + * addressed through offset on REGSB) + */ + orig = 0; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA && t != SBSS) + continue; + v = s->value; + if(v == 0) { + diag("%s: no size", s->name); + v = 1; + } + v = rnd(v, 4); + s->value = v; + if(v > MINSIZ) + continue; + if(v >= 16) + orig = rnd(orig, 16); + else if(v >= 8) + orig = rnd(orig, 8); + s->value = orig; + orig += v; + s->type = SDATA1; + } + + /* + * pass 2 + * assign large 'data' variables to data segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA) { + if(t == SDATA1) + s->type = SDATA; + continue; + } + v = s->value; + if(v >= 16) + orig = rnd(orig, 16); + else if(v >= 8) + orig = rnd(orig, 8); + s->value = orig; + orig += v; + } + + while(orig & 7) + orig++; + datsize = orig; + + /* + * pass 3 + * everything else to bss segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SBSS) + continue; + v = s->value; + if(v >= 16) + orig = rnd(orig, 16); + else if(v >= 8) + orig = rnd(orig, 8); + s->value = orig; + orig += v; + } + while(orig & 7) + orig++; + bsssize = orig-datsize; + + xdefine("setSB", SDATA, 0L); + xdefine("bdata", SDATA, 0L); + xdefine("edata", SDATA, datsize); + xdefine("end", SBSS, datsize+bsssize); + xdefine("etext", STEXT, 0L); +} + +Prog* +brchain(Prog *p) +{ + int i; + + for(i=0; i<20; i++) { + if(p == P || !isbranch(p->as)) + return p; + p = p->cond; + } + return P; +} + +void +follow(void) +{ + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + firstp = prg(); + lastp = firstp; + xfol(textp); + + firstp = firstp->link; + lastp->link = P; +} + +void +xfol(Prog *p) +{ + Prog *q, *r; + int a, i; + +loop: + if(p == P) + return; + a = p->as; + if(a == ATEXT) + curtext = p; + if(isbranch(a)) { + q = p->cond; + if(q != P) { + p->mark |= FOLL; + p = q; + if(!(p->mark & FOLL)) + goto loop; + } + } + if(p->mark & FOLL) { + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == lastp) + break; + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(isbranch(a) || isreturn(a)) + goto copy; + if(q->cond == nil || (q->cond->mark&FOLL)) + continue; + if(a != ABEQ && a != ABNE) + continue; + copy: + for(;;) { + r = prg(); + *r = *p; + if(!(r->mark&FOLL)) + print("cant happen 1\n"); + r->mark |= FOLL; + if(p != q) { + p = p->link; + lastp->link = r; + lastp = r; + continue; + } + lastp->link = r; + lastp = r; + if(isbranch(a) || isreturn(a)) + return; + r->as = a == ABNE? ABEQ: ABNE; + r->cond = p->link; + r->link = p->cond; + if(!(r->link->mark&FOLL)) + xfol(r->link); + if(!(r->cond->mark&FOLL)) + print("cant happen 2\n"); + return; + } + } + a = branchop(); + q = prg(); + q->as = a; + q->line = p->line; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->cond = p; + p = q; + } + p->mark |= FOLL; + lastp->link = p; + lastp = p; + if(isbranch(a) || isreturn(a)) + return; + if(p->cond != P) + if(!iscall(a) && p->link != P) { + q = brchain(p->link); + if(canfollow(a)) + if(q != P && (q->mark&FOLL)) { + p->as = relinv(a); + p->link = p->cond; + p->cond = q; + } + xfol(p->link); + q = brchain(p->cond); + if(q == P) + q = p->cond; + if(q->mark&FOLL) { + p->cond = q; + return; + } + p = q; + goto loop; + } + p = p->link; + goto loop; +} + +void +patch(void) +{ + long c, vexit; + Prog *p, *q; + Sym *s; + int a; + + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + mkfwd(); + s = lookup("exit", 0); + vexit = s->value; + for(p = firstp; p != P; p = p->link) { + a = p->as; + if(a == ATEXT) + curtext = p; + if((iscall(a) || isbranch(a) || isreturn(a)) && + p->to.type != D_BRANCH && p->to.sym != S) { + s = p->to.sym; + switch(s->type) { + default: + diag("undefined: %s\n%P", s->name, p); + s->type = STEXT; + s->value = vexit; + break; + case STEXT: + p->to.offset = s->value; + break; + case SUNDEF: + if(!iscall(p->as)) + diag("help: SUNDEF in AB || ARET"); + p->to.offset = 0; + p->cond = UP; + break; + } + p->to.type = D_BRANCH; + } + if(p->cond == UP) + continue; + if(p->to.type == D_BRANCH) + c = p->to.offset; + else if(p->from.type == D_BRANCH) + c = p->from.offset; + else + continue; + 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 %ld\n%P", c, p); + p->to.type = D_NONE; + } + p->cond = q; + } + + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->cond != P && p->cond != UP) { + p->cond = brloop(p->cond); + if(p->cond != P){ + if(p->to.type == D_BRANCH) + p->to.offset = p->cond->pc; + if(p->from.type == D_BRANCH) + p->from.offset = p->cond->pc; + } + } + } +} + +#define LOG 6 +void +mkfwd(void) +{ + Prog *p; + long dwn[LOG], cnt[LOG], i; + 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) +{ + Prog *q; + int c; + + for(c=0; p!=P;) { + if(!isbranch(p->as)) + return p; + q = p->cond; + if(q <= p) { + c++; + if(q == p || c > 5000) + break; + } + p = q; + } + return P; +} + +void +undef(void) +{ + int i; + Sym *s; + + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->type == SXREF) + diag("%s: not defined", s->name); +} |