xref: /inferno-os/utils/ld/elf.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
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
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
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
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
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
78 elf32sectab(void (*putl)(long))
79 {
80 	seek(cout, HEADR+textsize+datsize+symsize, 0);
81 	elf32shdr(putl, Stitext, Progbits, Salloc|Sexec, INITTEXT,
82 		HEADR, textsize, 0, 0, 0x10000, 0);
83 	elf32shdr(putl, Stidata, Progbits, Salloc|Swrite, INITDAT,
84 		HEADR+textsize, datsize, 0, 0, 0x10000, 0);
85 	elf32shdr(putl, Stistrtab, Strtab, 1 << 5, 0,
86 		HEADR+textsize+datsize+symsize+3*Shdr32sz, 14, 0, 0, 1, 0);
87 	elfstrtab();
88 }
89 
90 /* if addpsects > 0, putpsects must emit exactly that many psects. */
91 void
92 elf32(int mach, int bo, int addpsects, void (*putpsects)(Putl))
93 {
94 	ulong phydata;
95 	void (*putw)(long), (*putl)(long);
96 
97 	if(bo == ELFDATA2MSB){
98 		putw = wput;
99 		putl = lput;
100 	}else if(bo == ELFDATA2LSB){
101 		putw = wputl;
102 		putl = lputl;
103 	}else{
104 		print("elf32 byte order is mixed-endian\n");
105 		errorexit();
106 		return;
107 	}
108 
109 	elfident(bo, ELFCLASS32);
110 	putw(EXEC);
111 	putw(mach);
112 	putl(1L);			/* version = CURRENT */
113 	putl(entryvalue());		/* entry vaddr */
114 	putl(Ehdr32sz);			/* offset to first phdr */
115 	if(debug['S'])
116 		putl(HEADR+textsize+datsize+symsize); /* offset to first shdr */
117 	else
118 		putl(0);
119 	putl(0L);			/* flags */
120 	putw(Ehdr32sz);
121 	putw(Phdr32sz);
122 	putw(3 + addpsects);		/* # of Phdrs */
123 	putw(Shdr32sz);
124 	if(debug['S']){
125 		putw(3);		/* # of Shdrs */
126 		putw(2);		/* Shdr table index */
127 	}else{
128 		putw(0);
129 		putw(0);
130 	}
131 
132 	/*
133 	 * could include ELF headers in text -- 8l doesn't,
134 	 * but in theory it aids demand loading.
135 	 */
136 	elf32phdr(putl, PT_LOAD, HEADR, INITTEXT, INITTEXTP,
137 		textsize, textsize, R|X, INITRND);	/* text */
138 	/*
139 	 * we need INITDATP, but it has to be computed.
140 	 * assume distance between INITTEXT & INITTEXTP is also
141 	 * correct for INITDAT and INITDATP.
142 	 */
143 	phydata = INITDAT - (INITTEXT - INITTEXTP);
144 	elf32phdr(putl, PT_LOAD, HEADR+textsize, INITDAT, phydata,
145 		datsize, datsize+bsssize, R|W|X, INITRND); /* data */
146 	elf32phdr(putl, NOPTYPE, HEADR+textsize+datsize, 0, 0,
147 		symsize, lcsize, R, 4);			/* symbol table */
148 	if (addpsects > 0)
149 		putpsects(putl);
150 	cflush();
151 
152 	if(debug['S'])
153 		elf32sectab(putl);
154 }
155 
156 /*
157  * elf64
158  */
159 
160 void
161 elf64phdr(void (*putl)(long), void (*putll)(vlong), ulong type, uvlong off,
162 	uvlong vaddr, uvlong paddr, uvlong filesz, uvlong memsz, ulong prots,
163 	uvlong align)
164 {
165 	putl(type);
166 	putl(prots);
167 	putll(off);
168 	putll(vaddr);
169 	putll(paddr);
170 	putll(filesz);
171 	putll(memsz);
172 	putll(align);
173 }
174 
175 void
176 elf64shdr(void (*putl)(long), void (*putll)(vlong), ulong name, ulong type,
177 	uvlong flags, uvlong vaddr, uvlong off, uvlong sectsz, ulong link,
178 	ulong addnl, uvlong align, uvlong entsz)
179 {
180 	putl(name);
181 	putl(type);
182 	putll(flags);
183 	putll(vaddr);
184 	putll(off);
185 	putll(sectsz);
186 	putl(link);
187 	putl(addnl);
188 	putll(align);
189 	putll(entsz);
190 }
191 
192 static void
193 elf64sectab(void (*putl)(long), void (*putll)(vlong))
194 {
195 	seek(cout, HEADR+textsize+datsize+symsize, 0);
196 	elf64shdr(putl, putll, Stitext, Progbits, Salloc|Sexec, INITTEXT,
197 		HEADR, textsize, 0, 0, 0x10000, 0);
198 	elf64shdr(putl, putll, Stidata, Progbits, Salloc|Swrite, INITDAT,
199 		HEADR+textsize, datsize, 0, 0, 0x10000, 0);
200 	elf64shdr(putl, putll, Stistrtab, Strtab, 1 << 5, 0,
201 		HEADR+textsize+datsize+symsize+3*Shdr64sz, 14, 0, 0, 1, 0);
202 	elfstrtab();
203 }
204 
205 /* if addpsects > 0, putpsects must emit exactly that many psects. */
206 void
207 elf64(int mach, int bo, int addpsects, void (*putpsects)(Putl))
208 {
209 	uvlong phydata;
210 	void (*putw)(long), (*putl)(long);
211 	void (*putll)(vlong);
212 
213 	if(bo == ELFDATA2MSB){
214 		putw = wput;
215 		putl = lput;
216 		putll = llput;
217 	}else if(bo == ELFDATA2LSB){
218 		putw = wputl;
219 		putl = lputl;
220 		putll = llputl;
221 	}else{
222 		print("elf64 byte order is mixed-endian\n");
223 		errorexit();
224 		return;
225 	}
226 
227 	elfident(bo, ELFCLASS64);
228 	putw(EXEC);
229 	putw(mach);
230 	putl(1L);			/* version = CURRENT */
231 	putll(entryvalue());		/* entry vaddr */
232 	putll(Ehdr64sz);		/* offset to first phdr */
233 	if(debug['S'])
234 		putll(HEADR+textsize+datsize+symsize); /* offset to 1st shdr */
235 	else
236 		putll(0);
237 	putl(0L);			/* flags */
238 	putw(Ehdr64sz);
239 	putw(Phdr64sz);
240 	putw(3 + addpsects);		/* # of Phdrs */
241 	putw(Shdr64sz);
242 	if(debug['S']){
243 		putw(3);		/* # of Shdrs */
244 		putw(2);		/* Shdr table index */
245 	}else{
246 		putw(0);
247 		putw(0);
248 	}
249 
250 	elf64phdr(putl, putll, PT_LOAD, HEADR, INITTEXT, INITTEXTP,
251 		textsize, textsize, R|X, INITRND);	/* text */
252 	/*
253 	 * see 32-bit ELF case for physical data address computation.
254 	 */
255 	phydata = INITDAT - (INITTEXT - INITTEXTP);
256 	elf64phdr(putl, putll, PT_LOAD, HEADR+textsize, INITDAT, phydata,
257 		datsize, datsize+bsssize, R|W, INITRND); /* data */
258 	elf64phdr(putl, putll, NOPTYPE, HEADR+textsize+datsize, 0, 0,
259 		symsize, lcsize, R, 4);			/* symbol table */
260 	if (addpsects > 0)
261 		putpsects(putl);
262 	cflush();
263 
264 	if(debug['S'])
265 		elf64sectab(putl, putll);
266 }
267