#include "l.h" #define KIF "kernel interface file" static Prog *datp; static Sym *linkt; static Prog* newprg(int, Prog*); void kif(char *f) { long o; Prog *p, *q, *fp, *lp, *dp; Sym *s; s = lookup("__link", 0); if(s->type != 0){ diag("dynamic link table entry __link already defined\n"); errorexit(); } s->type = SBSS; s->value = sizeof(long*); linkt = s; fp = firstp; lp = lastp; dp = datap; objfile(f); if(fp != firstp || lp != lastp){ diag("code in %s %s\n", KIF, f); errorexit(); } p = datap; datap = dp; dp = P; for( ; p != P && p != datap; p = q){ q = p->link; p->link = dp; dp = p; } o = 0; s = S; for(p = dp; p != P; p = p->link){ if(p->as == ADYNT || p->as == AINIT){ diag("bad data type in %s %s\n", KIF, f); errorexit(); } if(s == S) s = p->from.sym; if(s != p->from.sym){ diag("more than one data item in %s %s\n", KIF, f); errorexit(); } if(o != p->from.offset){ diag("bad data size in %s %s\n", KIF, f); errorexit(); } if(p->to.sym == nil){ diag("bad pointer value in %s %s\n", KIF, f); errorexit(); } o += sizeof(long*); if(p->to.sym->type != SXREF){ diag("%s pointer value %s already defined\n", KIF, p->to.sym->name); errorexit(); } } datp = dp; } static Prog* newprg(int op, Prog* p) { Prog* q; q = prg(); q->as = op; q->line = p->line; q->pc = p->pc; q->reg = NREG; q->link = p->link; p->link = q; return q; } int dynfn(Sym *s) { int i, k; Prog *dp; k = -1; for(i = 0, dp = datp; dp != P; i++, dp = dp->link){ if(s == dp->to.sym){ k = i; break; } } return k; } int dyncall(Prog *p) { int k; Prog *q; if((k = dynfn(p->to.sym)) < 0) return 0; #define R 1 p->as = AMOVW; p->from.type = D_OREG; p->from.name = D_EXTERN; p->from.sym = linkt; p->from.offset = 0; p->reg = NREG; p->to.type = D_REG; p->to.name = D_NONE; p->to.sym = nil; p->to.reg = R; q = newprg(AMOVW, p); q->from.type = D_OREG; q->from.name = D_NONE; q->from.reg = R; q->from.offset = k*sizeof(long*); q->to.type = D_REG; q->to.reg = R; q = newprg(ABL, q); q->from.type = D_NONE; q->to.type = D_OREG; q->to.name = D_NONE; q->to.reg = R; q->to.offset = 0; #undef R return 1; } static struct relocinfo{ long n; long m; long *rel; } reloc[4]; void dynreloc(long a, int intext, Sym *s) { int i = 0, n; long *nrel; struct relocinfo *r; if(!intext) i = 2; if(s == S || s->type == STEXT || s->type == SLEAF) ; else if(s->type == SDATA || s->type == SDATA1 || s->type == SBSS) i++; else if(s->type == SXREF) return; else diag("help: dynreloc cannot cope\n"); r = &reloc[i]; if(r->n >= r->m){ n = r->m; r->m += 32; nrel = malloc(r->m*sizeof(long)); memmove(nrel, r->rel, n*sizeof(long)); free(r->rel); r->rel = nrel; } r->rel[r->n++] = a; } static void outrel(struct relocinfo *r) { int i, n = r->n; long *p; lput(n); for(i = 0, p = r->rel; i < n; i++, p++) lput(*p); } static void dreloc(void) { Prog *p; long a; for(p = datap; p != P; p = p->link){ if(p->to.type == D_CONST && p->to.sym){ if(isfnptr(&p->to) && dynfn(p->to.sym) >= 0) diag("cannot use interface function %s as a function pointer", p->to.sym->name); a = p->from.sym->value + p->from.offset + INITDAT; dynreloc(a, 0, p->to.sym); } /* print("%P\n", p); */ } } void asmdyn(void) { int i; Prog *p; Sym *s; char buf[32]; dreloc(); for(p = datp; p != P; p = p->link) p->to.sym->type = STEXT; // stop undefined messages at end lput(0xfedcba98); if(module != nil){ for(i = 0; module[i]; i++) cput(module[i]); } cput(0); if(module != nil){ strcpy(buf, module); strcat(buf, "end"); s = lookup(buf, 0); if(s->type == STEXT){ if(s->thumb) lput(s->value+1); // T bit else lput(s->value); } else lput(-1); } else lput(-1); if(linkt != S) lput(linkt->value); else lput(-1); if(module != nil){ strcpy(buf, module); strcat(buf, "modtab"); s = lookup(buf, 0); if(s == nil){ diag("missing module table: %s\n", buf); errorexit(); } lput(s->value); } else lput(-1); // [tt|td|dt|dd]reloc for(i = 0; i < 4; i++) outrel(&reloc[i]); } long dynentry(Sym *s) { char buf[32]; s->type = STEXT; // prevent error message if(module == nil) return -1; strcpy(buf, module); strcat(buf, "init"); /* for(p = buf; *p != 0; p++){ if(*p >= 'A' && *p <= 'Z') *p += 'a' - 'A'; } */ s = lookup(buf, 0); if(s->type == STEXT){ if(s->thumb) return s->value+1; // T bit else return s->value; } return -1; }