Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

/*
 * emit 32- or 64-bit elf headers for any architecture.
 * this is a component of ?l.
 */
#include "l.h"

enum {
        /* offsets into string table */
        Stitext         = 1,
        Stidata         = 7,
        Stistrtab       = 13,
};

void
elfident(int bo, int class)
{
        strnput("\177ELF", 4);          /* e_ident */
        cput(class);
        cput(bo);                       /* byte order */
        cput(1);                        /* version = CURRENT */
        if(debug['k']){                 /* boot/embedded/standalone */
                cput(255);
                cput(0);
        }
        else{
                cput(0);                /* osabi = SYSV */
                cput(0);                /* abiversion = 3 */
        }
        strnput("", 7);
}

void
elfstrtab(void)
{
        /* string table */
        cput(0);
        strnput(".text", 5);            /* +1 */
        cput(0);
        strnput(".data", 5);            /* +7 */
        cput(0);
        strnput(".strtab", 7);          /* +13 */
        cput(0);
        cput(0);
}

void
elf32phdr(void (*putl)(long), ulong type, ulong off, ulong vaddr, ulong paddr,
        ulong filesz, ulong memsz, ulong prots, ulong align)
{
        putl(type);
        putl(off);
        putl(vaddr);
        putl(paddr);
        putl(filesz);
        putl(memsz);
        putl(prots);
        putl(align);
}

void
elf32shdr(void (*putl)(long), ulong name, ulong type, ulong flags, ulong vaddr,
        ulong off, ulong sectsz, ulong link, ulong addnl, ulong align,
        ulong entsz)
{
        putl(name);
        putl(type);
        putl(flags);
        putl(vaddr);
        putl(off);
        putl(sectsz);
        putl(link);
        putl(addnl);
        putl(align);
        putl(entsz);
}

static void
elf32sectab(void (*putl)(long))
{
        seek(cout, HEADR+textsize+datsize+symsize, 0);
        elf32shdr(putl, Stitext, Progbits, Salloc|Sexec, INITTEXT,
                HEADR, textsize, 0, 0, 0x10000, 0);
        elf32shdr(putl, Stidata, Progbits, Salloc|Swrite, INITDAT,
                HEADR+textsize, datsize, 0, 0, 0x10000, 0);
        elf32shdr(putl, Stistrtab, Strtab, 1 << 5, 0,
                HEADR+textsize+datsize+symsize+3*Shdr32sz, 14, 0, 0, 1, 0);
        elfstrtab();
}

/* if addpsects > 0, putpsects must emit exactly that many psects. */
void
elf32(int mach, int bo, int addpsects, void (*putpsects)(Putl))
{
        ulong phydata;
        void (*putw)(long), (*putl)(long);

        if(bo == ELFDATA2MSB){
                putw = wput;
                putl = lput;
        }else if(bo == ELFDATA2LSB){
                putw = wputl;
                putl = lputl;
        }else{
                print("elf32 byte order is mixed-endian\n");
                errorexit();
                return;
        }

        elfident(bo, ELFCLASS32);
        putw(EXEC);
        putw(mach);
        putl(1L);                       /* version = CURRENT */
        putl(entryvalue());             /* entry vaddr */
        putl(Ehdr32sz);                 /* offset to first phdr */
        if(debug['S'])
                putl(HEADR+textsize+datsize+symsize); /* offset to first shdr */
        else
                putl(0);
        putl(0L);                       /* flags */
        putw(Ehdr32sz);
        putw(Phdr32sz);
        putw(3 + addpsects);            /* # of Phdrs */
        putw(Shdr32sz);
        if(debug['S']){
                putw(3);                /* # of Shdrs */
                putw(2);                /* Shdr table index */
        }else{
                putw(0);
                putw(0);
        }

        /*
         * could include ELF headers in text -- 8l doesn't,
         * but in theory it aids demand loading.
         */
        elf32phdr(putl, PT_LOAD, HEADR, INITTEXT, INITTEXTP,
                textsize, textsize, R|X, INITRND);      /* text */
        /*
         * we need INITDATP, but it has to be computed.
         * assume distance between INITTEXT & INITTEXTP is also
         * correct for INITDAT and INITDATP.
         */
        phydata = INITDAT - (INITTEXT - INITTEXTP);
        elf32phdr(putl, PT_LOAD, HEADR+textsize, INITDAT, phydata,
                datsize, datsize+bsssize, R|W|X, INITRND); /* data */
        elf32phdr(putl, NOPTYPE, HEADR+textsize+datsize, 0, 0,
                symsize, lcsize, R, 4);                 /* symbol table */
        if (addpsects > 0)
                putpsects(putl);
        cflush();

        if(debug['S'])
                elf32sectab(putl);
}

/*
 * elf64
 */

void
elf64phdr(void (*putl)(long), void (*putll)(vlong), ulong type, uvlong off,
        uvlong vaddr, uvlong paddr, uvlong filesz, uvlong memsz, ulong prots,
        uvlong align)
{
        putl(type);             
        putl(prots);            
        putll(off);             
        putll(vaddr);   
        putll(paddr);   
        putll(filesz);  
        putll(memsz);   
        putll(align);           
}

void
elf64shdr(void (*putl)(long), void (*putll)(vlong), ulong name, ulong type,
        uvlong flags, uvlong vaddr, uvlong off, uvlong sectsz, ulong link,
        ulong addnl, uvlong align, uvlong entsz)
{
        putl(name);
        putl(type);
        putll(flags);
        putll(vaddr);
        putll(off);
        putll(sectsz);
        putl(link);
        putl(addnl);
        putll(align);
        putll(entsz);
}

static void
elf64sectab(void (*putl)(long), void (*putll)(vlong))
{
        seek(cout, HEADR+textsize+datsize+symsize, 0);
        elf64shdr(putl, putll, Stitext, Progbits, Salloc|Sexec, INITTEXT,
                HEADR, textsize, 0, 0, 0x10000, 0);
        elf64shdr(putl, putll, Stidata, Progbits, Salloc|Swrite, INITDAT,
                HEADR+textsize, datsize, 0, 0, 0x10000, 0);
        elf64shdr(putl, putll, Stistrtab, Strtab, 1 << 5, 0,
                HEADR+textsize+datsize+symsize+3*Shdr64sz, 14, 0, 0, 1, 0);
        elfstrtab();
}

/* if addpsects > 0, putpsects must emit exactly that many psects. */
void
elf64(int mach, int bo, int addpsects, void (*putpsects)(Putl))
{
        uvlong phydata;
        void (*putw)(long), (*putl)(long);
        void (*putll)(vlong);

        if(bo == ELFDATA2MSB){
                putw = wput;
                putl = lput;
                putll = llput;
        }else if(bo == ELFDATA2LSB){
                putw = wputl;
                putl = lputl;
                putll = llputl;
        }else{
                print("elf64 byte order is mixed-endian\n");
                errorexit();
                return;
        }

        elfident(bo, ELFCLASS64);
        putw(EXEC);
        putw(mach);
        putl(1L);                       /* version = CURRENT */
        putll(entryvalue());            /* entry vaddr */
        putll(Ehdr64sz);                /* offset to first phdr */
        if(debug['S'])
                putll(HEADR+textsize+datsize+symsize); /* offset to 1st shdr */
        else
                putll(0);
        putl(0L);                       /* flags */
        putw(Ehdr64sz);
        putw(Phdr64sz);
        putw(3 + addpsects);            /* # of Phdrs */
        putw(Shdr64sz);
        if(debug['S']){
                putw(3);                /* # of Shdrs */
                putw(2);                /* Shdr table index */
        }else{
                putw(0);
                putw(0);
        }

        elf64phdr(putl, putll, PT_LOAD, HEADR, INITTEXT, INITTEXTP,
                textsize, textsize, R|X, INITRND);      /* text */
        /*
         * see 32-bit ELF case for physical data address computation.
         */
        phydata = INITDAT - (INITTEXT - INITTEXTP);
        elf64phdr(putl, putll, PT_LOAD, HEADR+textsize, INITDAT, phydata,
                datsize, datsize+bsssize, R|W, INITRND); /* data */
        elf64phdr(putl, putll, NOPTYPE, HEADR+textsize+datsize, 0, 0,
                symsize, lcsize, R, 4);                 /* symbol table */
        if (addpsects > 0)
                putpsects(putl);
        cflush();

        if(debug['S'])
                elf64sectab(putl, putll);
}