diff options
| author | forsyth <forsyth@lavoro.terzarima.net> | 2013-06-03 21:01:14 +0000 |
|---|---|---|
| committer | forsyth <forsyth@lavoro.terzarima.net> | 2013-06-03 21:01:14 +0000 |
| commit | 45a20ab721a513710138340faff3d59a31c3e01e (patch) | |
| tree | eea29d2684c51cc73725b8992a2125bede48e118 /utils/ld/elf.c | |
| parent | cd8e99851af33e52bcdf8faf34f9d4e62fa0cbaf (diff) | |
sync compilers with Plan 9
remove 1[acl] 2[acl]
Diffstat (limited to 'utils/ld/elf.c')
| -rw-r--r-- | utils/ld/elf.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/utils/ld/elf.c b/utils/ld/elf.c new file mode 100644 index 00000000..2b25c57c --- /dev/null +++ b/utils/ld/elf.c @@ -0,0 +1,266 @@ +/* + * 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); +} |
