ref: a920c765f2b4130590fb5971a50690b21664957a
dir: /utils/ld/elf.c/
/* * 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); }