xref: /plan9/sys/src/cmd/8l/elf.c (revision 4fa3bc585d2612e6bb007aaec8a7fe23f7fa9940)
1*4fa3bc58SDavid du Colombier /*
2*4fa3bc58SDavid du Colombier  * emit 32- or 64-bit elf headers for any architecture.
3*4fa3bc58SDavid du Colombier  * this is a component of ?l.
4*4fa3bc58SDavid du Colombier  */
5*4fa3bc58SDavid du Colombier #include "l.h"
6*4fa3bc58SDavid du Colombier 
7*4fa3bc58SDavid du Colombier enum {
8*4fa3bc58SDavid du Colombier 	/* offsets into string table */
9*4fa3bc58SDavid du Colombier 	Stitext		= 1,
10*4fa3bc58SDavid du Colombier 	Stidata		= 7,
11*4fa3bc58SDavid du Colombier 	Stistrtab	= 13,
12*4fa3bc58SDavid du Colombier };
13*4fa3bc58SDavid du Colombier 
14*4fa3bc58SDavid du Colombier void
elfident(int bo,int class)15*4fa3bc58SDavid du Colombier elfident(int bo, int class)
16*4fa3bc58SDavid du Colombier {
17*4fa3bc58SDavid du Colombier 	strnput("\177ELF", 4);		/* e_ident */
18*4fa3bc58SDavid du Colombier 	cput(class);
19*4fa3bc58SDavid du Colombier 	cput(bo);			/* byte order */
20*4fa3bc58SDavid du Colombier 	cput(1);			/* version = CURRENT */
21*4fa3bc58SDavid du Colombier 	if(debug['k']){			/* boot/embedded/standalone */
22*4fa3bc58SDavid du Colombier 		cput(255);
23*4fa3bc58SDavid du Colombier 		cput(0);
24*4fa3bc58SDavid du Colombier 	}
25*4fa3bc58SDavid du Colombier 	else{
26*4fa3bc58SDavid du Colombier 		cput(0);		/* osabi = SYSV */
27*4fa3bc58SDavid du Colombier 		cput(0);		/* abiversion = 3 */
28*4fa3bc58SDavid du Colombier 	}
29*4fa3bc58SDavid du Colombier 	strnput("", 7);
30*4fa3bc58SDavid du Colombier }
31*4fa3bc58SDavid du Colombier 
32*4fa3bc58SDavid du Colombier void
elfstrtab(void)33*4fa3bc58SDavid du Colombier elfstrtab(void)
34*4fa3bc58SDavid du Colombier {
35*4fa3bc58SDavid du Colombier 	/* string table */
36*4fa3bc58SDavid du Colombier 	cput(0);
37*4fa3bc58SDavid du Colombier 	strnput(".text", 5);		/* +1 */
38*4fa3bc58SDavid du Colombier 	cput(0);
39*4fa3bc58SDavid du Colombier 	strnput(".data", 5);		/* +7 */
40*4fa3bc58SDavid du Colombier 	cput(0);
41*4fa3bc58SDavid du Colombier 	strnput(".strtab", 7);		/* +13 */
42*4fa3bc58SDavid du Colombier 	cput(0);
43*4fa3bc58SDavid du Colombier 	cput(0);
44*4fa3bc58SDavid du Colombier }
45*4fa3bc58SDavid du Colombier 
46*4fa3bc58SDavid du Colombier void
elf32phdr(void (* putl)(long),ulong type,ulong off,ulong vaddr,ulong paddr,ulong filesz,ulong memsz,ulong prots,ulong align)47*4fa3bc58SDavid du Colombier elf32phdr(void (*putl)(long), ulong type, ulong off, ulong vaddr, ulong paddr,
48*4fa3bc58SDavid du Colombier 	ulong filesz, ulong memsz, ulong prots, ulong align)
49*4fa3bc58SDavid du Colombier {
50*4fa3bc58SDavid du Colombier 	putl(type);
51*4fa3bc58SDavid du Colombier 	putl(off);
52*4fa3bc58SDavid du Colombier 	putl(vaddr);
53*4fa3bc58SDavid du Colombier 	putl(paddr);
54*4fa3bc58SDavid du Colombier 	putl(filesz);
55*4fa3bc58SDavid du Colombier 	putl(memsz);
56*4fa3bc58SDavid du Colombier 	putl(prots);
57*4fa3bc58SDavid du Colombier 	putl(align);
58*4fa3bc58SDavid du Colombier }
59*4fa3bc58SDavid du Colombier 
60*4fa3bc58SDavid 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)61*4fa3bc58SDavid du Colombier elf32shdr(void (*putl)(long), ulong name, ulong type, ulong flags, ulong vaddr,
62*4fa3bc58SDavid du Colombier 	ulong off, ulong sectsz, ulong link, ulong addnl, ulong align,
63*4fa3bc58SDavid du Colombier 	ulong entsz)
64*4fa3bc58SDavid du Colombier {
65*4fa3bc58SDavid du Colombier 	putl(name);
66*4fa3bc58SDavid du Colombier 	putl(type);
67*4fa3bc58SDavid du Colombier 	putl(flags);
68*4fa3bc58SDavid du Colombier 	putl(vaddr);
69*4fa3bc58SDavid du Colombier 	putl(off);
70*4fa3bc58SDavid du Colombier 	putl(sectsz);
71*4fa3bc58SDavid du Colombier 	putl(link);
72*4fa3bc58SDavid du Colombier 	putl(addnl);
73*4fa3bc58SDavid du Colombier 	putl(align);
74*4fa3bc58SDavid du Colombier 	putl(entsz);
75*4fa3bc58SDavid du Colombier }
76*4fa3bc58SDavid du Colombier 
77*4fa3bc58SDavid du Colombier static void
elf32sectab(void (* putl)(long))78*4fa3bc58SDavid du Colombier elf32sectab(void (*putl)(long))
79*4fa3bc58SDavid du Colombier {
80*4fa3bc58SDavid du Colombier 	seek(cout, HEADR+textsize+datsize+symsize, 0);
81*4fa3bc58SDavid du Colombier 	elf32shdr(putl, Stitext, Progbits, Salloc|Sexec, INITTEXT,
82*4fa3bc58SDavid du Colombier 		HEADR, textsize, 0, 0, 0x10000, 0);
83*4fa3bc58SDavid du Colombier 	elf32shdr(putl, Stidata, Progbits, Salloc|Swrite, INITDAT,
84*4fa3bc58SDavid du Colombier 		HEADR+textsize, datsize, 0, 0, 0x10000, 0);
85*4fa3bc58SDavid du Colombier 	elf32shdr(putl, Stistrtab, Strtab, 1 << 5, 0,
86*4fa3bc58SDavid du Colombier 		HEADR+textsize+datsize+symsize+3*Shdr32sz, 14, 0, 0, 1, 0);
87*4fa3bc58SDavid du Colombier 	elfstrtab();
88*4fa3bc58SDavid du Colombier }
89*4fa3bc58SDavid du Colombier 
90*4fa3bc58SDavid du Colombier /* if addpsects > 0, putpsects must emit exactly that many psects. */
91*4fa3bc58SDavid du Colombier void
elf32(int mach,int bo,int addpsects,void (* putpsects)(Putl))92*4fa3bc58SDavid du Colombier elf32(int mach, int bo, int addpsects, void (*putpsects)(Putl))
93*4fa3bc58SDavid du Colombier {
94*4fa3bc58SDavid du Colombier 	ulong phydata;
95*4fa3bc58SDavid du Colombier 	void (*putw)(long), (*putl)(long);
96*4fa3bc58SDavid du Colombier 
97*4fa3bc58SDavid du Colombier 	if(bo == ELFDATA2MSB){
98*4fa3bc58SDavid du Colombier 		putw = wput;
99*4fa3bc58SDavid du Colombier 		putl = lput;
100*4fa3bc58SDavid du Colombier 	}else if(bo == ELFDATA2LSB){
101*4fa3bc58SDavid du Colombier 		putw = wputl;
102*4fa3bc58SDavid du Colombier 		putl = lputl;
103*4fa3bc58SDavid du Colombier 	}else{
104*4fa3bc58SDavid du Colombier 		print("elf32 byte order is mixed-endian\n");
105*4fa3bc58SDavid du Colombier 		errorexit();
106*4fa3bc58SDavid du Colombier 		return;
107*4fa3bc58SDavid du Colombier 	}
108*4fa3bc58SDavid du Colombier 
109*4fa3bc58SDavid du Colombier 	elfident(bo, ELFCLASS32);
110*4fa3bc58SDavid du Colombier 	putw(EXEC);
111*4fa3bc58SDavid du Colombier 	putw(mach);
112*4fa3bc58SDavid du Colombier 	putl(1L);			/* version = CURRENT */
113*4fa3bc58SDavid du Colombier 	putl(entryvalue());		/* entry vaddr */
114*4fa3bc58SDavid du Colombier 	putl(Ehdr32sz);			/* offset to first phdr */
115*4fa3bc58SDavid du Colombier 	if(debug['S'])
116*4fa3bc58SDavid du Colombier 		putl(HEADR+textsize+datsize+symsize); /* offset to first shdr */
117*4fa3bc58SDavid du Colombier 	else
118*4fa3bc58SDavid du Colombier 		putl(0);
119*4fa3bc58SDavid du Colombier 	putl(0L);			/* flags */
120*4fa3bc58SDavid du Colombier 	putw(Ehdr32sz);
121*4fa3bc58SDavid du Colombier 	putw(Phdr32sz);
122*4fa3bc58SDavid du Colombier 	putw(3 + addpsects);		/* # of Phdrs */
123*4fa3bc58SDavid du Colombier 	putw(Shdr32sz);
124*4fa3bc58SDavid du Colombier 	if(debug['S']){
125*4fa3bc58SDavid du Colombier 		putw(3);		/* # of Shdrs */
126*4fa3bc58SDavid du Colombier 		putw(2);		/* Shdr table index */
127*4fa3bc58SDavid du Colombier 	}else{
128*4fa3bc58SDavid du Colombier 		putw(0);
129*4fa3bc58SDavid du Colombier 		putw(0);
130*4fa3bc58SDavid du Colombier 	}
131*4fa3bc58SDavid du Colombier 
132*4fa3bc58SDavid du Colombier 	/*
133*4fa3bc58SDavid du Colombier 	 * could include ELF headers in text -- 8l doesn't,
134*4fa3bc58SDavid du Colombier 	 * but in theory it aids demand loading.
135*4fa3bc58SDavid du Colombier 	 */
136*4fa3bc58SDavid du Colombier 	elf32phdr(putl, PT_LOAD, HEADR, INITTEXT, INITTEXTP,
137*4fa3bc58SDavid du Colombier 		textsize, textsize, R|X, INITRND);	/* text */
138*4fa3bc58SDavid du Colombier 	/*
139*4fa3bc58SDavid du Colombier 	 * we need INITDATP, but it has to be computed.
140*4fa3bc58SDavid du Colombier 	 * assume distance between INITTEXT & INITTEXTP is also
141*4fa3bc58SDavid du Colombier 	 * correct for INITDAT and INITDATP.
142*4fa3bc58SDavid du Colombier 	 */
143*4fa3bc58SDavid du Colombier 	phydata = INITDAT - (INITTEXT - INITTEXTP);
144*4fa3bc58SDavid du Colombier 	elf32phdr(putl, PT_LOAD, HEADR+textsize, INITDAT, phydata,
145*4fa3bc58SDavid du Colombier 		datsize, datsize+bsssize, R|W|X, INITRND); /* data */
146*4fa3bc58SDavid du Colombier 	elf32phdr(putl, NOPTYPE, HEADR+textsize+datsize, 0, 0,
147*4fa3bc58SDavid du Colombier 		symsize, lcsize, R, 4);			/* symbol table */
148*4fa3bc58SDavid du Colombier 	if (addpsects > 0)
149*4fa3bc58SDavid du Colombier 		putpsects(putl);
150*4fa3bc58SDavid du Colombier 	cflush();
151*4fa3bc58SDavid du Colombier 
152*4fa3bc58SDavid du Colombier 	if(debug['S'])
153*4fa3bc58SDavid du Colombier 		elf32sectab(putl);
154*4fa3bc58SDavid du Colombier }
155*4fa3bc58SDavid du Colombier 
156*4fa3bc58SDavid du Colombier /*
157*4fa3bc58SDavid du Colombier  * elf64
158*4fa3bc58SDavid du Colombier  */
159*4fa3bc58SDavid du Colombier 
160*4fa3bc58SDavid 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)161*4fa3bc58SDavid du Colombier elf64phdr(void (*putl)(long), void (*putll)(vlong), ulong type, uvlong off,
162*4fa3bc58SDavid du Colombier 	uvlong vaddr, uvlong paddr, uvlong filesz, uvlong memsz, ulong prots,
163*4fa3bc58SDavid du Colombier 	uvlong align)
164*4fa3bc58SDavid du Colombier {
165*4fa3bc58SDavid du Colombier 	putl(type);
166*4fa3bc58SDavid du Colombier 	putl(prots);
167*4fa3bc58SDavid du Colombier 	putll(off);
168*4fa3bc58SDavid du Colombier 	putll(vaddr);
169*4fa3bc58SDavid du Colombier 	putll(paddr);
170*4fa3bc58SDavid du Colombier 	putll(filesz);
171*4fa3bc58SDavid du Colombier 	putll(memsz);
172*4fa3bc58SDavid du Colombier 	putll(align);
173*4fa3bc58SDavid du Colombier }
174*4fa3bc58SDavid du Colombier 
175*4fa3bc58SDavid 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)176*4fa3bc58SDavid du Colombier elf64shdr(void (*putl)(long), void (*putll)(vlong), ulong name, ulong type,
177*4fa3bc58SDavid du Colombier 	uvlong flags, uvlong vaddr, uvlong off, uvlong sectsz, ulong link,
178*4fa3bc58SDavid du Colombier 	ulong addnl, uvlong align, uvlong entsz)
179*4fa3bc58SDavid du Colombier {
180*4fa3bc58SDavid du Colombier 	putl(name);
181*4fa3bc58SDavid du Colombier 	putl(type);
182*4fa3bc58SDavid du Colombier 	putll(flags);
183*4fa3bc58SDavid du Colombier 	putll(vaddr);
184*4fa3bc58SDavid du Colombier 	putll(off);
185*4fa3bc58SDavid du Colombier 	putll(sectsz);
186*4fa3bc58SDavid du Colombier 	putl(link);
187*4fa3bc58SDavid du Colombier 	putl(addnl);
188*4fa3bc58SDavid du Colombier 	putll(align);
189*4fa3bc58SDavid du Colombier 	putll(entsz);
190*4fa3bc58SDavid du Colombier }
191*4fa3bc58SDavid du Colombier 
192*4fa3bc58SDavid du Colombier static void
elf64sectab(void (* putl)(long),void (* putll)(vlong))193*4fa3bc58SDavid du Colombier elf64sectab(void (*putl)(long), void (*putll)(vlong))
194*4fa3bc58SDavid du Colombier {
195*4fa3bc58SDavid du Colombier 	seek(cout, HEADR+textsize+datsize+symsize, 0);
196*4fa3bc58SDavid du Colombier 	elf64shdr(putl, putll, Stitext, Progbits, Salloc|Sexec, INITTEXT,
197*4fa3bc58SDavid du Colombier 		HEADR, textsize, 0, 0, 0x10000, 0);
198*4fa3bc58SDavid du Colombier 	elf64shdr(putl, putll, Stidata, Progbits, Salloc|Swrite, INITDAT,
199*4fa3bc58SDavid du Colombier 		HEADR+textsize, datsize, 0, 0, 0x10000, 0);
200*4fa3bc58SDavid du Colombier 	elf64shdr(putl, putll, Stistrtab, Strtab, 1 << 5, 0,
201*4fa3bc58SDavid du Colombier 		HEADR+textsize+datsize+symsize+3*Shdr64sz, 14, 0, 0, 1, 0);
202*4fa3bc58SDavid du Colombier 	elfstrtab();
203*4fa3bc58SDavid du Colombier }
204*4fa3bc58SDavid du Colombier 
205*4fa3bc58SDavid du Colombier /* if addpsects > 0, putpsects must emit exactly that many psects. */
206*4fa3bc58SDavid du Colombier void
elf64(int mach,int bo,int addpsects,void (* putpsects)(Putl))207*4fa3bc58SDavid du Colombier elf64(int mach, int bo, int addpsects, void (*putpsects)(Putl))
208*4fa3bc58SDavid du Colombier {
209*4fa3bc58SDavid du Colombier 	uvlong phydata;
210*4fa3bc58SDavid du Colombier 	void (*putw)(long), (*putl)(long);
211*4fa3bc58SDavid du Colombier 	void (*putll)(vlong);
212*4fa3bc58SDavid du Colombier 
213*4fa3bc58SDavid du Colombier 	if(bo == ELFDATA2MSB){
214*4fa3bc58SDavid du Colombier 		putw = wput;
215*4fa3bc58SDavid du Colombier 		putl = lput;
216*4fa3bc58SDavid du Colombier 		putll = llput;
217*4fa3bc58SDavid du Colombier 	}else if(bo == ELFDATA2LSB){
218*4fa3bc58SDavid du Colombier 		putw = wputl;
219*4fa3bc58SDavid du Colombier 		putl = lputl;
220*4fa3bc58SDavid du Colombier 		putll = llputl;
221*4fa3bc58SDavid du Colombier 	}else{
222*4fa3bc58SDavid du Colombier 		print("elf64 byte order is mixed-endian\n");
223*4fa3bc58SDavid du Colombier 		errorexit();
224*4fa3bc58SDavid du Colombier 		return;
225*4fa3bc58SDavid du Colombier 	}
226*4fa3bc58SDavid du Colombier 
227*4fa3bc58SDavid du Colombier 	elfident(bo, ELFCLASS64);
228*4fa3bc58SDavid du Colombier 	putw(EXEC);
229*4fa3bc58SDavid du Colombier 	putw(mach);
230*4fa3bc58SDavid du Colombier 	putl(1L);			/* version = CURRENT */
231*4fa3bc58SDavid du Colombier 	putll(entryvalue());		/* entry vaddr */
232*4fa3bc58SDavid du Colombier 	putll(Ehdr64sz);		/* offset to first phdr */
233*4fa3bc58SDavid du Colombier 	if(debug['S'])
234*4fa3bc58SDavid du Colombier 		putll(HEADR+textsize+datsize+symsize); /* offset to 1st shdr */
235*4fa3bc58SDavid du Colombier 	else
236*4fa3bc58SDavid du Colombier 		putll(0);
237*4fa3bc58SDavid du Colombier 	putl(0L);			/* flags */
238*4fa3bc58SDavid du Colombier 	putw(Ehdr64sz);
239*4fa3bc58SDavid du Colombier 	putw(Phdr64sz);
240*4fa3bc58SDavid du Colombier 	putw(3 + addpsects);		/* # of Phdrs */
241*4fa3bc58SDavid du Colombier 	putw(Shdr64sz);
242*4fa3bc58SDavid du Colombier 	if(debug['S']){
243*4fa3bc58SDavid du Colombier 		putw(3);		/* # of Shdrs */
244*4fa3bc58SDavid du Colombier 		putw(2);		/* Shdr table index */
245*4fa3bc58SDavid du Colombier 	}else{
246*4fa3bc58SDavid du Colombier 		putw(0);
247*4fa3bc58SDavid du Colombier 		putw(0);
248*4fa3bc58SDavid du Colombier 	}
249*4fa3bc58SDavid du Colombier 
250*4fa3bc58SDavid du Colombier 	elf64phdr(putl, putll, PT_LOAD, HEADR, INITTEXT, INITTEXTP,
251*4fa3bc58SDavid du Colombier 		textsize, textsize, R|X, INITRND);	/* text */
252*4fa3bc58SDavid du Colombier 	/*
253*4fa3bc58SDavid du Colombier 	 * see 32-bit ELF case for physical data address computation.
254*4fa3bc58SDavid du Colombier 	 */
255*4fa3bc58SDavid du Colombier 	phydata = INITDAT - (INITTEXT - INITTEXTP);
256*4fa3bc58SDavid du Colombier 	elf64phdr(putl, putll, PT_LOAD, HEADR+textsize, INITDAT, phydata,
257*4fa3bc58SDavid du Colombier 		datsize, datsize+bsssize, R|W, INITRND); /* data */
258*4fa3bc58SDavid du Colombier 	elf64phdr(putl, putll, NOPTYPE, HEADR+textsize+datsize, 0, 0,
259*4fa3bc58SDavid du Colombier 		symsize, lcsize, R, 4);			/* symbol table */
260*4fa3bc58SDavid du Colombier 	if (addpsects > 0)
261*4fa3bc58SDavid du Colombier 		putpsects(putl);
262*4fa3bc58SDavid du Colombier 	cflush();
263*4fa3bc58SDavid du Colombier 
264*4fa3bc58SDavid du Colombier 	if(debug['S'])
265*4fa3bc58SDavid du Colombier 		elf64sectab(putl, putll);
266*4fa3bc58SDavid du Colombier }
267