Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include        "l.h"

#define Dbufslop        100

long
entryvalue(void)
{
        char *a;
        Sym *s;

        a = INITENTRY;
        if(*a >= '0' && *a <= '9')
                return atolwhex(a);
        s = lookup(a, 0);
        if(s->type == 0)
                return INITTEXT;
        switch(s->type) {
        case STEXT:
                break;
        case SDATA:
                if(dlm)
                        return s->value+INITDAT;
        default:
                diag("entry not text: %s", s->name);
        }
        return s->value;
}

/* these need to take long arguments to be compatible with elf.c */
void
wputl(long w)
{
        cput(w);
        cput(w>>8);
}

void
wput(long w)
{
        cput(w>>8);
        cput(w);
}

void
lput(long l)
{
        cput(l>>24);
        cput(l>>16);
        cput(l>>8);
        cput(l);
}

void
lputl(long l)
{
        cput(l);
        cput(l>>8);
        cput(l>>16);
        cput(l>>24);
}

void
llput(vlong v)
{
        lput(v>>32);
        lput(v);
}

void
llputl(vlong v)
{
        lputl(v);
        lputl(v>>32);
}

void
strnput(char *s, int n)
{
        for(; *s && n > 0; s++){
                cput(*s);
                n--;
        }
        while(n > 0){
                cput(0);
                n--;
        }
}

void
asmb(void)
{
        Prog *p;
        long v, magic;
        int a;
        uchar *op1;

        if(debug['v'])
                Bprint(&bso, "%5.2f asmb\n", cputime());
        Bflush(&bso);

        seek(cout, HEADR, 0);
        pc = INITTEXT;
        curp = firstp;
        for(p = firstp; p != P; p = p->link) {
                if(p->as == ATEXT)
                        curtext = p;
                if(p->pc != pc) {
                        if(!debug['a'])
                                print("%P\n", curp);
                        diag("phase error %lux sb %lux in %s", p->pc, pc, TNAME);
                        pc = p->pc;
                }
                curp = p;
                asmins(p);
                if(cbc < sizeof(and))
                        cflush();
                a = (andptr - and);
                if(debug['a']) {
                        Bprint(&bso, pcstr, pc);
                        for(op1 = and; op1 < andptr; op1++)
                                Bprint(&bso, "%.2ux", *op1 & 0xff);
                        Bprint(&bso, "\t%P\n", curp);
                }
                if(dlm) {
                        if(p->as == ATEXT)
                                reloca = nil;
                        else if(reloca != nil)
                                diag("reloc failure: %P", curp);
                }
                memmove(cbp, and, a);
                cbp += a;
                pc += a;
                cbc -= a;
        }
        cflush();
        switch(HEADTYPE) {
        default:
                diag("unknown header type %ld", HEADTYPE);
        case 0:
                seek(cout, rnd(HEADR+textsize, 8192), 0);
                break;
        case 1:
                textsize = rnd(HEADR+textsize, 4096)-HEADR;
                seek(cout, textsize+HEADR, 0);
                break;
        case 2:
        case 5:
                seek(cout, HEADR+textsize, 0);
                break;
        case 3:
        case 4:
                seek(cout, HEADR+rnd(textsize, INITRND), 0);
                break;
        }

        if(debug['v'])
                Bprint(&bso, "%5.2f datblk\n", cputime());
        Bflush(&bso);

        if(dlm){
                char buf[8];

                write(cout, buf, INITDAT-textsize);
                textsize = INITDAT;
        }

        for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
                if(datsize-v > sizeof(buf)-Dbufslop)
                        datblk(v, sizeof(buf)-Dbufslop);
                else
                        datblk(v, datsize-v);
        }

        symsize = 0;
        spsize = 0;
        lcsize = 0;
        if(!debug['s']) {
                if(debug['v'])
                        Bprint(&bso, "%5.2f sym\n", cputime());
                Bflush(&bso);
                switch(HEADTYPE) {
                default:
                case 0:
                        seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0);
                        break;
                case 1:
                        seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
                        break;
                case 2:
                case 5:
                        seek(cout, HEADR+textsize+datsize, 0);
                        break;
                case 3:
                case 4:
                        debug['s'] = 1;
                        break;
                }
                if(!debug['s'])
                        asmsym();
                if(debug['v'])
                        Bprint(&bso, "%5.2f sp\n", cputime());
                Bflush(&bso);
                if(debug['v'])
                        Bprint(&bso, "%5.2f pc\n", cputime());
                Bflush(&bso);
                if(!debug['s'])
                        asmlc();
                if(dlm)
                        asmdyn();
                cflush();
        }
        else if(dlm){
                seek(cout, HEADR+textsize+datsize, 0);
                asmdyn();
                cflush();
        }
        if(debug['v'])
                Bprint(&bso, "%5.2f headr\n", cputime());
        Bflush(&bso);
        seek(cout, 0L, 0);
        switch(HEADTYPE) {
        default:
        case 0:  /* garbage */
                lput(0x160L<<16);               /* magic and sections */
                lput(0L);                       /* time and date */
                lput(rnd(HEADR+textsize, 4096)+datsize);
                lput(symsize);                  /* nsyms */
                lput((0x38L<<16)|7L);           /* size of optional hdr and flags */
                lput((0413<<16)|0437L);         /* magic and version */
                lput(rnd(HEADR+textsize, 4096));/* sizes */
                lput(datsize);
                lput(bsssize);
                lput(entryvalue());             /* va of entry */
                lput(INITTEXT-HEADR);           /* va of base of text */
                lput(INITDAT);                  /* va of base of data */
                lput(INITDAT+datsize);          /* va of base of bss */
                lput(~0L);                      /* gp reg mask */
                lput(0L);
                lput(0L);
                lput(0L);
                lput(0L);
                lput(~0L);                      /* gp value ?? */
                break;
        case 1: /* unix coff */
                /*
                 * file header
                 */
                lputl(0x0004014c);              /* 4 sections, magic */
                lputl(0);                       /* unix time stamp */
                lputl(0);                       /* symbol table */
                lputl(0);                       /* nsyms */
                lputl(0x0003001c);              /* flags, sizeof a.out header */
                /*
                 * a.out header
                 */
                lputl(0x10b);                   /* magic, version stamp */
                lputl(rnd(textsize, INITRND));  /* text sizes */
                lputl(datsize);                 /* data sizes */
                lputl(bsssize);                 /* bss sizes */
                lput(entryvalue());             /* va of entry */
                lputl(INITTEXT);                /* text start */
                lputl(INITDAT);                 /* data start */
                /*
                 * text section header
                 */
                strnput(".text", 8);
                lputl(HEADR);                   /* pa */
                lputl(HEADR);                   /* va */
                lputl(textsize);                /* text size */
                lputl(HEADR);                   /* file offset */
                lputl(0);                       /* relocation */
                lputl(0);                       /* line numbers */
                lputl(0);                       /* relocation, line numbers */
                lputl(0x20);                    /* flags text only */
                /*
                 * data section header
                 */
                strnput(".data", 8);
                lputl(INITDAT);                 /* pa */
                lputl(INITDAT);                 /* va */
                lputl(datsize);                 /* data size */
                lputl(HEADR+textsize);          /* file offset */
                lputl(0);                       /* relocation */
                lputl(0);                       /* line numbers */
                lputl(0);                       /* relocation, line numbers */
                lputl(0x40);                    /* flags data only */
                /*
                 * bss section header
                 */
                strnput(".bss", 8);
                lputl(INITDAT+datsize);         /* pa */
                lputl(INITDAT+datsize);         /* va */
                lputl(bsssize);                 /* bss size */
                lputl(0);                       /* file offset */
                lputl(0);                       /* relocation */
                lputl(0);                       /* line numbers */
                lputl(0);                       /* relocation, line numbers */
                lputl(0x80);                    /* flags bss only */
                /*
                 * comment section header
                 */
                strnput(".comment", 8);
                lputl(0);                       /* pa */
                lputl(0);                       /* va */
                lputl(symsize+lcsize);          /* comment size */
                lputl(HEADR+textsize+datsize);  /* file offset */
                lputl(HEADR+textsize+datsize);  /* offset of syms */
                lputl(HEADR+textsize+datsize+symsize);/* offset of line numbers */
                lputl(0);                       /* relocation, line numbers */
                lputl(0x200);                   /* flags comment only */
                break;
        case 2: /* plan9 */
                magic = 4*11*11+7;
                if(dlm)
                        magic |= 0x80000000;
                lput(magic);                    /* magic */
                lput(textsize);                 /* sizes */
                lput(datsize);
                lput(bsssize);
                lput(symsize);                  /* nsyms */
                lput(entryvalue());             /* va of entry */
                lput(spsize);                   /* sp offsets */
                lput(lcsize);                   /* line offsets */
                break;
        case 3:
                /* MS-DOS .COM */
                break;
        case 4:
                /* fake MS-DOS .EXE */
                v = rnd(HEADR+textsize, INITRND)+datsize;
                wputl(0x5A4D);                  /* 'MZ' */
                wputl(v % 512);                 /* bytes in last page */
                wputl(rnd(v, 512)/512);         /* total number of pages */
                wputl(0x0000);                  /* number of reloc items */
                v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
                wputl(v/16);                    /* size of header */
                wputl(0x0000);                  /* minimum allocation */
                wputl(0xFFFF);                  /* maximum allocation */
                wputl(0x0000);                  /* initial ss value */
                wputl(0x0100);                  /* initial sp value */
                wputl(0x0000);                  /* complemented checksum */
                v = entryvalue();
                wputl(v);                       /* initial ip value (!) */
                wputl(0x0000);                  /* initial cs value */
                wputl(0x0000);
                wputl(0x0000);
                wputl(0x003E);                  /* reloc table offset */
                wputl(0x0000);                  /* overlay number */
                break;
        case 5:
                elf32(I386, ELFDATA2LSB, 0, nil);
                break;
        }
        cflush();
}

void
cflush(void)
{
        int n;

        n = sizeof(buf.cbuf) - cbc;
        if(n)
                write(cout, buf.cbuf, n);
        cbp = buf.cbuf;
        cbc = sizeof(buf.cbuf);
}

void
datblk(long s, long n)
{
        Prog *p;
        char *cast;
        long l, fl, j;
        int i, c;

        memset(buf.dbuf, 0, n+Dbufslop);
        for(p = datap; p != P; p = p->link) {
                curp = p;
                l = p->from.sym->value + p->from.offset - s;
                c = p->from.scale;
                i = 0;
                if(l < 0) {
                        if(l+c <= 0)
                                continue;
                        while(l < 0) {
                                l++;
                                i++;
                        }
                }
                if(l >= n)
                        continue;
                if(p->as != AINIT && p->as != ADYNT) {
                        for(j=l+(c-i)-1; j>=l; j--)
                                if(buf.dbuf[j]) {
                                        print("%P\n", p);
                                        diag("multiple initialization");
                                        break;
                                }
                }
                switch(p->to.type) {
                case D_FCONST:
                        switch(c) {
                        default:
                        case 4:
                                fl = ieeedtof(&p->to.ieee);
                                cast = (char*)&fl;
                                if(debug['a'] && i == 0) {
                                        Bprint(&bso, pcstr, l+s+INITDAT);
                                        for(j=0; j<c; j++)
                                                Bprint(&bso, "%.2ux", cast[fnuxi4[j]] & 0xff);
                                        Bprint(&bso, "\t%P\n", curp);
                                }
                                for(; i<c; i++) {
                                        buf.dbuf[l] = cast[fnuxi4[i]];
                                        l++;
                                }
                                break;
                        case 8:
                                cast = (char*)&p->to.ieee;
                                if(debug['a'] && i == 0) {
                                        Bprint(&bso, pcstr, l+s+INITDAT);
                                        for(j=0; j<c; j++)
                                                Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff);
                                        Bprint(&bso, "\t%P\n", curp);
                                }
                                for(; i<c; i++) {
                                        buf.dbuf[l] = cast[fnuxi8[i]];
                                        l++;
                                }
                                break;
                        }
                        break;

                case D_SCONST:
                        if(debug['a'] && i == 0) {
                                Bprint(&bso, pcstr, l+s+INITDAT);
                                for(j=0; j<c; j++)
                                        Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff);
                                Bprint(&bso, "\t%P\n", curp);
                        }
                        for(; i<c; i++) {
                                buf.dbuf[l] = p->to.scon[i];
                                l++;
                        }
                        break;
                default:
                        fl = p->to.offset;
                        if(p->to.type == D_ADDR) {
                                if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
                                        diag("DADDR type%P", p);
                                if(p->to.sym) {
                                        if(p->to.sym->type == SUNDEF)
                                                ckoff(p->to.sym, fl);
                                        fl += p->to.sym->value;
                                        if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
                                                fl += INITDAT;
                                        if(dlm)
                                                dynreloc(p->to.sym, l+s+INITDAT, 1);
                                }
                        }
                        cast = (char*)&fl;
                        switch(c) {
                        default:
                                diag("bad nuxi %d %d\n%P", c, i, curp);
                                break;
                        case 1:
                                if(debug['a'] && i == 0) {
                                        Bprint(&bso, pcstr, l+s+INITDAT);
                                        for(j=0; j<c; j++)
                                                Bprint(&bso, "%.2ux", cast[inuxi1[j]] & 0xff);
                                        Bprint(&bso, "\t%P\n", curp);
                                }
                                for(; i<c; i++) {
                                        buf.dbuf[l] = cast[inuxi1[i]];
                                        l++;
                                }
                                break;
                        case 2:
                                if(debug['a'] && i == 0) {
                                        Bprint(&bso, pcstr, l+s+INITDAT);
                                        for(j=0; j<c; j++)
                                                Bprint(&bso, "%.2ux", cast[inuxi2[j]] & 0xff);
                                        Bprint(&bso, "\t%P\n", curp);
                                }
                                for(; i<c; i++) {
                                        buf.dbuf[l] = cast[inuxi2[i]];
                                        l++;
                                }
                                break;
                        case 4:
                                if(debug['a'] && i == 0) {
                                        Bprint(&bso, pcstr, l+s+INITDAT);
                                        for(j=0; j<c; j++)
                                                Bprint(&bso, "%.2ux", cast[inuxi4[j]] & 0xff);
                                        Bprint(&bso, "\t%P\n", curp);
                                }
                                for(; i<c; i++) {
                                        buf.dbuf[l] = cast[inuxi4[i]];
                                        l++;
                                }
                                break;
                        }
                        break;
                }
        }
        write(cout, buf.dbuf, n);
}

long
rnd(long 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;
}