140d01547SDavid du Colombier /*
240d01547SDavid du Colombier * emit 32- or 64-bit elf headers for any architecture.
340d01547SDavid du Colombier * this is a component of ?l.
440d01547SDavid du Colombier */
540d01547SDavid du Colombier #include "l.h"
640d01547SDavid du Colombier
740d01547SDavid du Colombier enum {
840d01547SDavid du Colombier /* offsets into string table */
940d01547SDavid du Colombier Stitext = 1,
1040d01547SDavid du Colombier Stidata = 7,
1140d01547SDavid du Colombier Stistrtab = 13,
1240d01547SDavid du Colombier };
1340d01547SDavid du Colombier
1440d01547SDavid du Colombier void
elfident(int bo,int class)1540d01547SDavid du Colombier elfident(int bo, int class)
1640d01547SDavid du Colombier {
1740d01547SDavid du Colombier strnput("\177ELF", 4); /* e_ident */
1840d01547SDavid du Colombier cput(class);
1940d01547SDavid du Colombier cput(bo); /* byte order */
2040d01547SDavid du Colombier cput(1); /* version = CURRENT */
2140d01547SDavid du Colombier if(debug['k']){ /* boot/embedded/standalone */
2240d01547SDavid du Colombier cput(255);
2340d01547SDavid du Colombier cput(0);
2440d01547SDavid du Colombier }
2540d01547SDavid du Colombier else{
2640d01547SDavid du Colombier cput(0); /* osabi = SYSV */
2740d01547SDavid du Colombier cput(0); /* abiversion = 3 */
2840d01547SDavid du Colombier }
2940d01547SDavid du Colombier strnput("", 7);
3040d01547SDavid du Colombier }
3140d01547SDavid du Colombier
3240d01547SDavid du Colombier void
elfstrtab(void)3340d01547SDavid du Colombier elfstrtab(void)
3440d01547SDavid du Colombier {
3540d01547SDavid du Colombier /* string table */
3640d01547SDavid du Colombier cput(0);
3740d01547SDavid du Colombier strnput(".text", 5); /* +1 */
3840d01547SDavid du Colombier cput(0);
3940d01547SDavid du Colombier strnput(".data", 5); /* +7 */
4040d01547SDavid du Colombier cput(0);
4140d01547SDavid du Colombier strnput(".strtab", 7); /* +13 */
4240d01547SDavid du Colombier cput(0);
4340d01547SDavid du Colombier cput(0);
4440d01547SDavid du Colombier }
4540d01547SDavid du Colombier
4640d01547SDavid du Colombier void
elf32phdr(void (* putl)(long),ulong type,ulong off,ulong vaddr,ulong paddr,ulong filesz,ulong memsz,ulong prots,ulong align)4740d01547SDavid du Colombier elf32phdr(void (*putl)(long), ulong type, ulong off, ulong vaddr, ulong paddr,
4840d01547SDavid du Colombier ulong filesz, ulong memsz, ulong prots, ulong align)
4940d01547SDavid du Colombier {
5040d01547SDavid du Colombier putl(type);
5140d01547SDavid du Colombier putl(off);
5240d01547SDavid du Colombier putl(vaddr);
5340d01547SDavid du Colombier putl(paddr);
5440d01547SDavid du Colombier putl(filesz);
5540d01547SDavid du Colombier putl(memsz);
5640d01547SDavid du Colombier putl(prots);
5740d01547SDavid du Colombier putl(align);
5840d01547SDavid du Colombier }
5940d01547SDavid du Colombier
6040d01547SDavid du Colombier 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)6140d01547SDavid du Colombier elf32shdr(void (*putl)(long), ulong name, ulong type, ulong flags, ulong vaddr,
6240d01547SDavid du Colombier ulong off, ulong sectsz, ulong link, ulong addnl, ulong align,
6340d01547SDavid du Colombier ulong entsz)
6440d01547SDavid du Colombier {
6540d01547SDavid du Colombier putl(name);
6640d01547SDavid du Colombier putl(type);
6740d01547SDavid du Colombier putl(flags);
6840d01547SDavid du Colombier putl(vaddr);
6940d01547SDavid du Colombier putl(off);
7040d01547SDavid du Colombier putl(sectsz);
7140d01547SDavid du Colombier putl(link);
7240d01547SDavid du Colombier putl(addnl);
7340d01547SDavid du Colombier putl(align);
7440d01547SDavid du Colombier putl(entsz);
7540d01547SDavid du Colombier }
7640d01547SDavid du Colombier
7740d01547SDavid du Colombier static void
elf32sectab(void (* putl)(long))7840d01547SDavid du Colombier elf32sectab(void (*putl)(long))
7940d01547SDavid du Colombier {
8040d01547SDavid du Colombier seek(cout, HEADR+textsize+datsize+symsize, 0);
81*faeb65a8SDavid du Colombier elf32shdr(putl, 0, 0, 0, 0,
82*faeb65a8SDavid du Colombier 0, 0, 0, 0, 0, 0);
8340d01547SDavid du Colombier elf32shdr(putl, Stitext, Progbits, Salloc|Sexec, INITTEXT,
84*faeb65a8SDavid du Colombier HEADR, textsize, 0, 0, INITRND, 0);
8540d01547SDavid du Colombier elf32shdr(putl, Stidata, Progbits, Salloc|Swrite, INITDAT,
86*faeb65a8SDavid du Colombier HEADR+textsize, datsize, 0, 0, INITRND, 0);
8740d01547SDavid du Colombier elf32shdr(putl, Stistrtab, Strtab, 1 << 5, 0,
88*faeb65a8SDavid du Colombier HEADR+textsize+datsize+symsize+4*Shdr32sz, 22, 0, 0, 1, 0);
8940d01547SDavid du Colombier elfstrtab();
9040d01547SDavid du Colombier }
9140d01547SDavid du Colombier
9240d01547SDavid du Colombier /* if addpsects > 0, putpsects must emit exactly that many psects. */
9340d01547SDavid du Colombier void
elf32(int mach,int bo,int addpsects,void (* putpsects)(Putl))9440d01547SDavid du Colombier elf32(int mach, int bo, int addpsects, void (*putpsects)(Putl))
9540d01547SDavid du Colombier {
9640d01547SDavid du Colombier ulong phydata;
9740d01547SDavid du Colombier void (*putw)(long), (*putl)(long);
9840d01547SDavid du Colombier
9940d01547SDavid du Colombier if(bo == ELFDATA2MSB){
10040d01547SDavid du Colombier putw = wput;
10140d01547SDavid du Colombier putl = lput;
10240d01547SDavid du Colombier }else if(bo == ELFDATA2LSB){
10340d01547SDavid du Colombier putw = wputl;
10440d01547SDavid du Colombier putl = lputl;
10540d01547SDavid du Colombier }else{
10640d01547SDavid du Colombier print("elf32 byte order is mixed-endian\n");
10740d01547SDavid du Colombier errorexit();
10840d01547SDavid du Colombier return;
10940d01547SDavid du Colombier }
11040d01547SDavid du Colombier
11140d01547SDavid du Colombier elfident(bo, ELFCLASS32);
11240d01547SDavid du Colombier putw(EXEC);
11340d01547SDavid du Colombier putw(mach);
11440d01547SDavid du Colombier putl(1L); /* version = CURRENT */
11540d01547SDavid du Colombier putl(entryvalue()); /* entry vaddr */
11640d01547SDavid du Colombier putl(Ehdr32sz); /* offset to first phdr */
11740d01547SDavid du Colombier if(debug['S'])
11840d01547SDavid du Colombier putl(HEADR+textsize+datsize+symsize); /* offset to first shdr */
11940d01547SDavid du Colombier else
12040d01547SDavid du Colombier putl(0);
12140d01547SDavid du Colombier putl(0L); /* flags */
12240d01547SDavid du Colombier putw(Ehdr32sz);
12340d01547SDavid du Colombier putw(Phdr32sz);
12440d01547SDavid du Colombier putw(3 + addpsects); /* # of Phdrs */
12540d01547SDavid du Colombier putw(Shdr32sz);
12640d01547SDavid du Colombier if(debug['S']){
127*faeb65a8SDavid du Colombier putw(4); /* # of Shdrs */
128*faeb65a8SDavid du Colombier putw(3); /* Shdr table index */
12940d01547SDavid du Colombier }else{
13040d01547SDavid du Colombier putw(0);
13140d01547SDavid du Colombier putw(0);
13240d01547SDavid du Colombier }
13340d01547SDavid du Colombier
13440d01547SDavid du Colombier /*
13540d01547SDavid du Colombier * could include ELF headers in text -- 8l doesn't,
13640d01547SDavid du Colombier * but in theory it aids demand loading.
13740d01547SDavid du Colombier */
13840d01547SDavid du Colombier elf32phdr(putl, PT_LOAD, HEADR, INITTEXT, INITTEXTP,
13940d01547SDavid du Colombier textsize, textsize, R|X, INITRND); /* text */
14040d01547SDavid du Colombier /*
14140d01547SDavid du Colombier * we need INITDATP, but it has to be computed.
14240d01547SDavid du Colombier * assume distance between INITTEXT & INITTEXTP is also
14340d01547SDavid du Colombier * correct for INITDAT and INITDATP.
14440d01547SDavid du Colombier */
14540d01547SDavid du Colombier phydata = INITDAT - (INITTEXT - INITTEXTP);
14640d01547SDavid du Colombier elf32phdr(putl, PT_LOAD, HEADR+textsize, INITDAT, phydata,
14740d01547SDavid du Colombier datsize, datsize+bsssize, R|W|X, INITRND); /* data */
14840d01547SDavid du Colombier elf32phdr(putl, NOPTYPE, HEADR+textsize+datsize, 0, 0,
14940d01547SDavid du Colombier symsize, lcsize, R, 4); /* symbol table */
15040d01547SDavid du Colombier if (addpsects > 0)
15140d01547SDavid du Colombier putpsects(putl);
15240d01547SDavid du Colombier cflush();
15340d01547SDavid du Colombier
15440d01547SDavid du Colombier if(debug['S'])
15540d01547SDavid du Colombier elf32sectab(putl);
15640d01547SDavid du Colombier }
15740d01547SDavid du Colombier
15840d01547SDavid du Colombier /*
15940d01547SDavid du Colombier * elf64
16040d01547SDavid du Colombier */
16140d01547SDavid du Colombier
16240d01547SDavid du Colombier void
elf64phdr(void (* putl)(long),void (* putll)(vlong),ulong type,uvlong off,uvlong vaddr,uvlong paddr,uvlong filesz,uvlong memsz,ulong prots,uvlong align)16340d01547SDavid du Colombier elf64phdr(void (*putl)(long), void (*putll)(vlong), ulong type, uvlong off,
16440d01547SDavid du Colombier uvlong vaddr, uvlong paddr, uvlong filesz, uvlong memsz, ulong prots,
16540d01547SDavid du Colombier uvlong align)
16640d01547SDavid du Colombier {
16740d01547SDavid du Colombier putl(type);
16840d01547SDavid du Colombier putl(prots);
16940d01547SDavid du Colombier putll(off);
17040d01547SDavid du Colombier putll(vaddr);
17140d01547SDavid du Colombier putll(paddr);
17240d01547SDavid du Colombier putll(filesz);
17340d01547SDavid du Colombier putll(memsz);
17440d01547SDavid du Colombier putll(align);
17540d01547SDavid du Colombier }
17640d01547SDavid du Colombier
17740d01547SDavid du Colombier 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)17840d01547SDavid du Colombier elf64shdr(void (*putl)(long), void (*putll)(vlong), ulong name, ulong type,
17940d01547SDavid du Colombier uvlong flags, uvlong vaddr, uvlong off, uvlong sectsz, ulong link,
18040d01547SDavid du Colombier ulong addnl, uvlong align, uvlong entsz)
18140d01547SDavid du Colombier {
18240d01547SDavid du Colombier putl(name);
18340d01547SDavid du Colombier putl(type);
18440d01547SDavid du Colombier putll(flags);
18540d01547SDavid du Colombier putll(vaddr);
18640d01547SDavid du Colombier putll(off);
18740d01547SDavid du Colombier putll(sectsz);
18840d01547SDavid du Colombier putl(link);
18940d01547SDavid du Colombier putl(addnl);
19040d01547SDavid du Colombier putll(align);
19140d01547SDavid du Colombier putll(entsz);
19240d01547SDavid du Colombier }
19340d01547SDavid du Colombier
19440d01547SDavid du Colombier static void
elf64sectab(void (* putl)(long),void (* putll)(vlong))19540d01547SDavid du Colombier elf64sectab(void (*putl)(long), void (*putll)(vlong))
19640d01547SDavid du Colombier {
19740d01547SDavid du Colombier seek(cout, HEADR+textsize+datsize+symsize, 0);
198*faeb65a8SDavid du Colombier elf64shdr(putl, putll, 0, 0, 0, 0,
199*faeb65a8SDavid du Colombier 0, 0, 0, 0, 0, 0);
20040d01547SDavid du Colombier elf64shdr(putl, putll, Stitext, Progbits, Salloc|Sexec, INITTEXT,
201*faeb65a8SDavid du Colombier HEADR, textsize, 0, 0, INITRND, 0);
20240d01547SDavid du Colombier elf64shdr(putl, putll, Stidata, Progbits, Salloc|Swrite, INITDAT,
203*faeb65a8SDavid du Colombier HEADR+textsize, datsize, 0, 0, INITRND, 0);
20440d01547SDavid du Colombier elf64shdr(putl, putll, Stistrtab, Strtab, 1 << 5, 0,
205*faeb65a8SDavid du Colombier HEADR+textsize+datsize+symsize+4*Shdr64sz, 22, 0, 0, 1, 0);
20640d01547SDavid du Colombier elfstrtab();
20740d01547SDavid du Colombier }
20840d01547SDavid du Colombier
20940d01547SDavid du Colombier /* if addpsects > 0, putpsects must emit exactly that many psects. */
21040d01547SDavid du Colombier void
elf64(int mach,int bo,int addpsects,void (* putpsects)(Putl))21140d01547SDavid du Colombier elf64(int mach, int bo, int addpsects, void (*putpsects)(Putl))
21240d01547SDavid du Colombier {
21340d01547SDavid du Colombier uvlong phydata;
21440d01547SDavid du Colombier void (*putw)(long), (*putl)(long);
21540d01547SDavid du Colombier void (*putll)(vlong);
21640d01547SDavid du Colombier
21740d01547SDavid du Colombier if(bo == ELFDATA2MSB){
21840d01547SDavid du Colombier putw = wput;
21940d01547SDavid du Colombier putl = lput;
22040d01547SDavid du Colombier putll = llput;
22140d01547SDavid du Colombier }else if(bo == ELFDATA2LSB){
22240d01547SDavid du Colombier putw = wputl;
22340d01547SDavid du Colombier putl = lputl;
22440d01547SDavid du Colombier putll = llputl;
22540d01547SDavid du Colombier }else{
22640d01547SDavid du Colombier print("elf64 byte order is mixed-endian\n");
22740d01547SDavid du Colombier errorexit();
22840d01547SDavid du Colombier return;
22940d01547SDavid du Colombier }
23040d01547SDavid du Colombier
23140d01547SDavid du Colombier elfident(bo, ELFCLASS64);
23240d01547SDavid du Colombier putw(EXEC);
23340d01547SDavid du Colombier putw(mach);
23440d01547SDavid du Colombier putl(1L); /* version = CURRENT */
23540d01547SDavid du Colombier putll(entryvalue()); /* entry vaddr */
23640d01547SDavid du Colombier putll(Ehdr64sz); /* offset to first phdr */
23740d01547SDavid du Colombier if(debug['S'])
23840d01547SDavid du Colombier putll(HEADR+textsize+datsize+symsize); /* offset to 1st shdr */
23940d01547SDavid du Colombier else
24040d01547SDavid du Colombier putll(0);
24140d01547SDavid du Colombier putl(0L); /* flags */
24240d01547SDavid du Colombier putw(Ehdr64sz);
24340d01547SDavid du Colombier putw(Phdr64sz);
24440d01547SDavid du Colombier putw(3 + addpsects); /* # of Phdrs */
24540d01547SDavid du Colombier putw(Shdr64sz);
24640d01547SDavid du Colombier if(debug['S']){
247*faeb65a8SDavid du Colombier putw(4); /* # of Shdrs */
248*faeb65a8SDavid du Colombier putw(3); /* Shdr table index */
24940d01547SDavid du Colombier }else{
25040d01547SDavid du Colombier putw(0);
25140d01547SDavid du Colombier putw(0);
25240d01547SDavid du Colombier }
25340d01547SDavid du Colombier
25440d01547SDavid du Colombier elf64phdr(putl, putll, PT_LOAD, HEADR, INITTEXT, INITTEXTP,
25540d01547SDavid du Colombier textsize, textsize, R|X, INITRND); /* text */
25640d01547SDavid du Colombier /*
25740d01547SDavid du Colombier * see 32-bit ELF case for physical data address computation.
25840d01547SDavid du Colombier */
25940d01547SDavid du Colombier phydata = INITDAT - (INITTEXT - INITTEXTP);
26040d01547SDavid du Colombier elf64phdr(putl, putll, PT_LOAD, HEADR+textsize, INITDAT, phydata,
26140d01547SDavid du Colombier datsize, datsize+bsssize, R|W, INITRND); /* data */
26240d01547SDavid du Colombier elf64phdr(putl, putll, NOPTYPE, HEADR+textsize+datsize, 0, 0,
26340d01547SDavid du Colombier symsize, lcsize, R, 4); /* symbol table */
26440d01547SDavid du Colombier if (addpsects > 0)
26540d01547SDavid du Colombier putpsects(putl);
26640d01547SDavid du Colombier cflush();
26740d01547SDavid du Colombier
26840d01547SDavid du Colombier if(debug['S'])
26940d01547SDavid du Colombier elf64sectab(putl, putll);
27040d01547SDavid du Colombier }
271