summaryrefslogtreecommitdiff
path: root/src/cmd/5l/span.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/5l/span.c')
-rw-r--r--src/cmd/5l/span.c671
1 files changed, 233 insertions, 438 deletions
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
index a97af07f9..be0f5e8b3 100644
--- a/src/cmd/5l/span.c
+++ b/src/cmd/5l/span.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Instruction layout.
+
#include "l.h"
#include "../ld/lib.h"
@@ -52,9 +54,9 @@ ispad(Prog *p)
{
if(p->as != AMOVW)
return 0;
- if(p->from.type != D_REG || p->from.reg != REGSB)
+ if(p->from.type != D_REG || p->from.reg != REGTMP)
return 0;
- if(p->to.type != D_REG || p->to.reg != REGSB)
+ if(p->to.type != D_REG || p->to.reg != REGTMP)
return 0;
return 1;
}
@@ -100,7 +102,7 @@ fnpinc(Sym *s)
if(!debug['f'])
diag("fnptr == 0 in fnpinc");
if(s->foreign)
- diag("bad usage in fnpinc %s %d %d %d", s->name, s->used, s->foreign, s->thumb);
+ diag("bad usage in fnpinc %s %d %d", s->name, s->foreign, s->thumb);
return 0;
}
/* 0, 1, 2, 3 squared */
@@ -119,9 +121,9 @@ pad(Prog *p, int pc)
q->as = AMOVW;
q->line = p->line;
q->from.type = D_REG;
- q->from.reg = REGSB;
+ q->from.reg = REGTMP;
q->to.type = D_REG;
- q->to.reg = REGSB;
+ q->to.reg = REGTMP;
q->pc = pc;
q->link = p->link;
return q;
@@ -132,7 +134,7 @@ scan(Prog *op, Prog *p, int c)
{
Prog *q;
- for(q = op->link; q != p; q = q->link){
+ for(q = op->link; q != p && q != P; q = q->link){
q->pc = c;
c += oplook(q)->size;
nocache(q);
@@ -163,11 +165,12 @@ void
span(void)
{
Prog *p, *op;
- Sym *setext, *s;
Optab *o;
- int m, bflag, i;
- int32 c, otxt, v;
+ int m, bflag, i, v;
+ int32 c, otxt, out[6];
int lastthumb = -1;
+ Section *sect;
+ uchar *bp;
if(debug['v'])
Bprint(&bso, "%5.2f span\n", cputime());
@@ -176,61 +179,65 @@ span(void)
bflag = 0;
c = INITTEXT;
op = nil;
+ p = nil;
otxt = c;
- for(p = firstp; p != P; op = p, p = p->link) {
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
setarch(p);
p->pc = c;
- o = oplook(p);
- m = o->size;
- // must check literal pool here in case p generates many instructions
- if(blitrl){
- if(thumb && isbranch(p))
- pool.extra += brextra(p);
- if(checkpool(op, p->as == ACASE ? casesz(p) : m))
- c = p->pc = scan(op, p, c);
- }
- if(m == 0) {
- if(p->as == ATEXT) {
- if(blitrl && lastthumb != -1 && lastthumb != thumb){ // flush literal pool
- if(flushpool(op, 0, 1))
- c = p->pc = scan(op, p, c);
- }
- lastthumb = thumb;
- curtext = p;
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- /* need passes to resolve branches */
- if(c-otxt >= 1L<<17)
- bflag = 1;
- otxt = c;
- if(thumb && blitrl)
+ cursym->value = c;
+
+ lastthumb = thumb;
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ /* need passes to resolve branches */
+ if(c-otxt >= 1L<<17)
+ bflag = 1;
+ otxt = c;
+ if(thumb && blitrl)
+ pool.extra += brextra(p);
+
+ for(op = p, p = p->link; p != P; op = p, p = p->link) {
+ curp = p;
+ setarch(p);
+ p->pc = c;
+ o = oplook(p);
+ m = o->size;
+ // must check literal pool here in case p generates many instructions
+ if(blitrl){
+ if(thumb && isbranch(p))
pool.extra += brextra(p);
+ if(checkpool(op, p->as == ACASE ? casesz(p) : m))
+ c = p->pc = scan(op, p, c);
+ }
+ if(m == 0) {
+ diag("zero-width instruction\n%P", p);
continue;
}
- diag("zero-width instruction\n%P", p);
- continue;
- }
- switch(o->flag & (LFROM|LTO|LPOOL)) {
- case LFROM:
- addpool(p, &p->from);
- break;
- case LTO:
- addpool(p, &p->to);
- break;
- case LPOOL:
- if ((p->scond&C_SCOND) == 14)
+ switch(o->flag & (LFROM|LTO|LPOOL)) {
+ case LFROM:
+ addpool(p, &p->from);
+ break;
+ case LTO:
+ addpool(p, &p->to);
+ break;
+ case LPOOL:
+ if ((p->scond&C_SCOND) == 14)
+ flushpool(p, 0, 0);
+ break;
+ }
+ if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
flushpool(p, 0, 0);
- break;
+ c += m;
}
- if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
- flushpool(p, 0, 0);
- c += m;
- if(blitrl && p->link == P){
- if(thumb && isbranch(p))
- pool.extra += brextra(p);
- checkpool(p, 0);
+ if(blitrl){
+ if(thumb && isbranch(op))
+ pool.extra += brextra(op);
+ if(checkpool(op, 0))
+ c = scan(op, P, c);
}
+ cursym->size = c - cursym->value;
}
/*
@@ -244,48 +251,52 @@ span(void)
Bprint(&bso, "%5.2f span1\n", cputime());
bflag = 0;
c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- p->pc = c;
- if(thumb && isbranch(p))
- nocache(p);
- o = oplook(p);
-/* very larg branches
- if(o->type == 6 && p->cond) {
- otxt = p->cond->pc - c;
- if(otxt < 0)
- otxt = -otxt;
- if(otxt >= (1L<<17) - 10) {
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = p->cond;
- p->cond = q;
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = q->link->link;
- bflag = 1;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ cursym->value = c;
+ for(p = cursym->text; p != P; p = p->link) {
+ curp = p;
+ setarch(p);
+ p->pc = c;
+ if(thumb && isbranch(p))
+ nocache(p);
+ o = oplook(p);
+/* very large branches
+ if(o->type == 6 && p->cond) {
+ otxt = p->cond->pc - c;
+ if(otxt < 0)
+ otxt = -otxt;
+ if(otxt >= (1L<<17) - 10) {
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->cond = p->cond;
+ p->cond = q;
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->cond = q->link->link;
+ bflag = 1;
+ }
}
- }
*/
- m = o->size;
- if(m == 0) {
- if(p->as == ATEXT) {
- curtext = p;
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
+ diag("zero-width instruction\n%P", p);
continue;
}
- diag("zero-width instruction\n%P", p);
- continue;
+ c += m;
}
- c += m;
+ cursym->size = c - cursym->value;
}
}
@@ -304,107 +315,94 @@ span(void)
c = INITTEXT;
oop = op = nil;
again = 0;
- for(p = firstp; p != P; oop = op, op = p, p = p->link){
- setarch(p);
- if(p->pc != c)
- again = 1;
- p->pc = c;
- if(thumb && isbranch(p))
- nocache(p);
- o = oplook(p);
- m = o->size;
- if(passes == 1 && thumb && isbranch(p)){ // start conservative so unneeded alignment is not added
- if(p->as == ABL)
- m = 4;
- else
- m = 2;
- p->align = 0;
- }
- if(p->align){
- if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){
- if(ispad(op)){
- oop->link = p;
- op = oop;
- c -= 2;
- p->pc = c;
- }
- else{
- op->link = pad(op, c);
- op = op->link;
- c += 2;
- p->pc = c;
- }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ cursym->value = c;
+ for(p = cursym->text; p != P; oop = op, op = p, p = p->link) {
+ curp = p;
+ setarch(p);
+ if(p->pc != c)
again = 1;
+ p->pc = c;
+ if(thumb && isbranch(p))
+ nocache(p);
+ o = oplook(p);
+ m = o->size;
+ if(passes == 1 && thumb && isbranch(p)){ // start conservative so unneeded alignment is not added
+ if(p->as == ABL)
+ m = 4;
+ else
+ m = 2;
+ p->align = 0;
}
- }
- if(m == 0) {
- if(p->as == ATEXT) {
- curtext = p;
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- continue;
+ if(p->align){
+ if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){
+ if(ispad(op)){
+ oop->link = p;
+ op = oop;
+ c -= 2;
+ p->pc = c;
+ }
+ else{
+ op->link = pad(op, c);
+ op = op->link;
+ c += 2;
+ p->pc = c;
+ }
+ again = 1;
+ }
+ }
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
}
+ c += m;
}
- c += m;
+ cursym->size = c - cursym->value;
}
if(c != lastc || again){
lastc = c;
goto loop;
}
}
-
- if(0 && seenthumb){ // rm redundant padding - obsolete
- int d;
-
- op = nil;
- d = 0;
- for(p = firstp; p != P; op = p, p = p->link){
- p->pc -= d;
- if(p->as == ATEXT){
- if(p->from.sym != S)
- p->from.sym->value -= d;
-// if(p->from.sym != S) print("%s %ux %d %d %d\n", p->from.sym->name ? p->from.sym->name : "?", p->from.sym->value, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr);
- }
- if(ispad(p) && p->link != P && ispad(p->link)){
- op->link = p->link->link;
- d += 4;
- p = op;
+ c = rnd(c, 8);
+
+ /*
+ * lay out the code. all the pc-relative code references,
+ * even cross-function, are resolved now;
+ * only data references need to be relocated.
+ * with more work we could leave cross-function
+ * code references to be relocated too, and then
+ * perhaps we'd be able to parallelize the span loop above.
+ */
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ setarch(p);
+ autosize = p->to.offset + 4;
+ symgrow(cursym, cursym->size);
+
+ bp = cursym->p;
+ for(p = p->link; p != P; p = p->link) {
+ curp = p;
+ pc = p->pc;
+ curp = p;
+ o = oplook(p);
+ asmout(p, o, out);
+ for(i=0; i<o->size/4; i++) {
+ v = out[i];
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
}
}
- // print("%d bytes removed (padding)\n", d);
- c -= d;
}
-
- if(debug['t']) {
- /*
- * add strings to text segment
- */
- c = rnd(c, 8);
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type != SSTRING)
- continue;
- v = s->value;
- while(v & 3)
- v++;
- s->value = c;
- c += v;
- }
- }
-
- c = rnd(c, 8);
-
- setext = lookup("etext", 0);
- if(setext != S) {
- setext->value = c;
- textsize = c - INITTEXT;
- }
- if(INITRND)
- INITDAT = rnd(c, INITRND);
- if(debug['v'])
- Bprint(&bso, "tsize = %lux\n", textsize);
- Bflush(&bso);
+ sect = addsection(&segtext, ".text", 05);
+ sect->vaddr = INITTEXT;
+ sect->len = c - INITTEXT;
}
/*
@@ -437,7 +435,7 @@ flushpool(Prog *p, int skip, int force)
if(blitrl) {
if(skip){
- if(0 && skip==1)print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start);
+ if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
q = prg();
q->as = AB;
q->to.type = D_BRANCH;
@@ -523,10 +521,10 @@ xdefine(char *p, int t, int32 v)
Sym *s;
s = lookup(p, 0);
- if(s->type == 0 || s->type == SXREF) {
- s->type = t;
- s->value = v;
- }
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
}
int32
@@ -583,6 +581,38 @@ immhalf(int32 v)
return 0;
}
+int32
+symaddr(Sym *s)
+{
+ int32 v;
+
+ v = s->value;
+ switch(s->type) {
+ default:
+ diag("unexpected type %d in symaddr(%s)", s->type, s->name);
+ return 0;
+
+ case STEXT:
+/* TODO(rsc): what is this for?
+#ifdef CALLEEBX
+ v += fnpinc(s);
+#else
+ if(s->thumb)
+ v++; // T bit
+#endif
+*/
+ break;
+
+ case SELFDATA:
+ case SRODATA:
+ case SDATA:
+ case SBSS:
+ case SCONST:
+ break;
+ }
+ return v;
+}
+
int
aclass(Adr *a)
{
@@ -619,36 +649,9 @@ aclass(Adr *a)
}
s = a->sym;
t = s->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s",
- s->name, TNAME);
- s->type = SDATA;
- }
- if(dlm) {
- switch(t) {
- default:
- instoffset = s->value + a->offset + INITDAT;
- break;
- case SUNDEF:
- case STEXT:
- case SCONST:
- case SLEAF:
- case SSTRING:
- instoffset = s->value + a->offset;
- break;
- }
- return C_ADDR;
- }
- instoffset = s->value + a->offset - BIG;
- t = immaddr(instoffset);
- if(t) {
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFEXT : C_HEXT;
- if(immfloat(t))
- return C_FEXT;
- return C_SEXT;
- }
- return C_LEXT;
+ instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
+
case D_AUTO:
instoffset = autosize + a->offset;
t = immaddr(instoffset);
@@ -703,32 +706,17 @@ aclass(Adr *a)
case D_STATIC:
s = a->sym;
t = s->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s",
- s->name, TNAME);
- s->type = SDATA;
- }
- if(s->type == SFIXED) {
- instoffset = s->value + a->offset;
- return C_LCON;
- }
- instoffset = s->value + a->offset + INITDAT;
- if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF) {
- instoffset = s->value + a->offset;
-#ifdef CALLEEBX
- instoffset += fnpinc(s);
-#else
- if(s->thumb)
- instoffset++; // T bit
-#endif
- return C_LCON;
- }
- return C_LCON;
+ instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
}
return C_GOK;
case D_FCONST:
- return C_FCON;
+ if(chipzero(&a->ieee) >= 0)
+ return C_ZFCON;
+ if(chipfloat(&a->ieee) >= 0)
+ return C_SFCON;
+ return C_LFCON;
case D_CONST:
case D_CONST2:
@@ -753,37 +741,7 @@ aclass(Adr *a)
if(s == S)
break;
t = s->type;
- switch(t) {
- case 0:
- case SXREF:
- diag("undefined external: %s in %s",
- s->name, TNAME);
- s->type = SDATA;
- break;
- case SFIXED:
- instoffset = s->value + a->offset;
- return C_LCON;
- case SUNDEF:
- case STEXT:
- case SSTRING:
- case SCONST:
- case SLEAF:
- instoffset = s->value + a->offset;
-#ifdef CALLEEBX
- instoffset += fnpinc(s);
-#else
- if(s->thumb)
- instoffset++; // T bit
-#endif
- return C_LCON;
- }
- if(!dlm) {
- instoffset = s->value + a->offset - BIG;
- t = immrot(instoffset);
- if(t && instoffset != 0)
- return C_RECON;
- }
- instoffset = s->value + a->offset + INITDAT;
+ instoffset = 0; // s.b. unused but just in case
return C_LCON;
case D_AUTO:
@@ -895,21 +853,11 @@ cmp(int a, int b)
if(b == C_RACON)
return 1;
break;
- case C_LECON:
- if(b == C_RECON)
+ case C_LFCON:
+ if(b == C_ZFCON || b == C_SFCON)
return 1;
break;
- case C_HFEXT:
- return b == C_HEXT || b == C_FEXT;
- case C_FEXT:
- case C_HEXT:
- return b == C_HFEXT;
- case C_SEXT:
- return cmp(C_HFEXT, b);
- case C_LEXT:
- return cmp(C_SEXT, b);
-
case C_HFAUTO:
return b == C_HAUTO || b == C_FAUTO;
case C_FAUTO:
@@ -1091,17 +1039,20 @@ buildop(void)
break;
case AMOVFW:
- oprange[AMOVWF] = oprange[r];
- oprange[AMOVWD] = oprange[r];
oprange[AMOVDW] = oprange[r];
break;
+ case AMOVWF:
+ oprange[AMOVWD] = oprange[r];
+ break;
+
case AMULL:
oprange[AMULA] = oprange[r];
oprange[AMULAL] = oprange[r];
oprange[AMULLU] = oprange[r];
oprange[AMULALU] = oprange[r];
break;
+
case ALDREX:
case ASTREX:
break;
@@ -1146,159 +1097,3 @@ buildrep(int x, int as)
oprange[as].start = 0;
}
*/
-
-enum{
- ABSD = 0,
- ABSU = 1,
- RELD = 2,
- RELU = 3,
-};
-
-int modemap[4] = { 0, 1, -1, 2, };
-
-typedef struct Reloc Reloc;
-
-struct Reloc
-{
- int n;
- int t;
- uchar *m;
- uint32 *a;
-};
-
-Reloc rels;
-
-static void
-grow(Reloc *r)
-{
- int t;
- uchar *m, *nm;
- uint32 *a, *na;
-
- t = r->t;
- r->t += 64;
- m = r->m;
- a = r->a;
- r->m = nm = malloc(r->t*sizeof(uchar));
- r->a = na = malloc(r->t*sizeof(uint32));
- memmove(nm, m, t*sizeof(uchar));
- memmove(na, a, t*sizeof(uint32));
- free(m);
- free(a);
-}
-
-void
-dynreloc(Sym *s, int32 v, int abs)
-{
- int i, k, n;
- uchar *m;
- uint32 *a;
- Reloc *r;
-
- if(v&3)
- diag("bad relocation address");
- v >>= 2;
- if(s != S && s->type == SUNDEF)
- k = abs ? ABSU : RELU;
- else
- k = abs ? ABSD : RELD;
- /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, k); */
- k = modemap[k];
- r = &rels;
- n = r->n;
- if(n >= r->t)
- grow(r);
- m = r->m;
- a = r->a;
- for(i = n; i > 0; i--){
- if(v < a[i-1]){ /* happens occasionally for data */
- m[i] = m[i-1];
- a[i] = a[i-1];
- }
- else
- break;
- }
- m[i] = k;
- a[i] = v;
- r->n++;
-}
-
-static int
-sput(char *s)
-{
- char *p;
-
- p = s;
- while(*s)
- cput(*s++);
- cput(0);
- return s-p+1;
-}
-
-void
-asmdyn()
-{
- int i, n, t, c;
- Sym *s;
- uint32 la, ra, *a;
- vlong off;
- uchar *m;
- Reloc *r;
-
- cflush();
- off = seek(cout, 0, 1);
- lput(0);
- t = 0;
- lput(imports);
- t += 4;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->type == SUNDEF){
- lput(s->sig);
- t += 4;
- t += sput(s->name);
- }
-
- la = 0;
- r = &rels;
- n = r->n;
- m = r->m;
- a = r->a;
- lput(n);
- t += 4;
- for(i = 0; i < n; i++){
- ra = *a-la;
- if(*a < la)
- diag("bad relocation order");
- if(ra < 256)
- c = 0;
- else if(ra < 65536)
- c = 1;
- else
- c = 2;
- cput((c<<6)|*m++);
- t++;
- if(c == 0){
- cput(ra);
- t++;
- }
- else if(c == 1){
- wput(ra);
- t += 2;
- }
- else{
- lput(ra);
- t += 4;
- }
- la = *a++;
- }
-
- cflush();
- seek(cout, off, 0);
- lput(t);
-
- if(debug['v']){
- Bprint(&bso, "import table entries = %d\n", imports);
- Bprint(&bso, "export table entries = %d\n", exports);
- }
-}