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