xref: /titanic_44/usr/src/uts/intel/ia32/krtld/kobj_boot.c (revision 9dd0f810214fdc8e1af881a9a5c4b6927629ff9e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Bootstrap the linker/loader.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/bootconf.h>
34 #include <sys/link.h>
35 #include <sys/auxv.h>
36 #include <sys/kobj.h>
37 #include <sys/elf.h>
38 #include <sys/bootsvcs.h>
39 #include <sys/kobj_impl.h>
40 
41 #if !defined(__GNUC__)
42 
43 /*
44  * We don't use the global offset table, but
45  * ld may throw in an UNDEFINED reference in
46  * our symbol table.
47  */
48 
49 #pragma weak _GLOBAL_OFFSET_TABLE_
50 
51 #else
52 
53 /*
54  * We -do- use the global offset table, but only by
55  * accident -- when you tell gcc to emit PIC code,
56  * it -always- generates a reference to the GOT in
57  * a register, even if the compilation unit never
58  * uses it.
59  *
60  * Rumoured to be fixed in a later version of gcc..
61  */
62 
63 long	_GLOBAL_OFFSET_TABLE_[1];
64 
65 #endif
66 
67 #define	MASK(n)		((1<<(n))-1)
68 #define	IN_RANGE(v, n)	((-(1<<((n)-1))) <= (v) && (v) < (1<<((n)-1)))
69 
70 #define	roundup		ALIGN
71 
72 /*
73  * Boot transfers control here. At this point,
74  * we haven't relocated our own symbols, so the
75  * world (as we know it) is pretty small right now.
76  */
77 void
78 _kobj_boot(
79 	struct boot_syscalls *syscallp,
80 	void *dvec,
81 	struct bootops *bootops,
82 	Boot *ebp)
83 {
84 	Shdr *section[24];	/* cache */
85 	val_t bootaux[BA_NUM];
86 	struct bootops *bop;
87 	Phdr *phdr;
88 	auxv_t *auxv = NULL;
89 	Shdr *sh;
90 	Half sh_num;
91 	uint_t end, edata = 0;
92 	int i;
93 
94 	bop = (dvec) ? *(struct bootops **)bootops : bootops;
95 
96 	for (i = 0; i < BA_NUM; i++)
97 		bootaux[i].ba_val = NULL;
98 
99 	/*
100 	 * Check the bootstrap vector.
101 	 */
102 	for (; ebp->eb_tag != EB_NULL; ebp++) {
103 		switch (ebp->eb_tag) {
104 		case EB_AUXV:
105 			auxv = (auxv_t *)ebp->eb_un.eb_ptr;
106 			break;
107 		case EB_DYNAMIC:
108 			bootaux[BA_DYNAMIC].ba_ptr = (void *)ebp->eb_un.eb_ptr;
109 			break;
110 		default:
111 			break;
112 		}
113 	}
114 
115 	if (auxv == NULL)
116 		return;
117 
118 	/*
119 	 * Now the aux vector.
120 	 */
121 	for (; auxv->a_type != AT_NULL; auxv++) {
122 		switch (auxv->a_type) {
123 		case AT_PHDR:
124 			bootaux[BA_PHDR].ba_ptr = auxv->a_un.a_ptr;
125 			break;
126 		case AT_PHENT:
127 			bootaux[BA_PHENT].ba_val = auxv->a_un.a_val;
128 			break;
129 		case AT_PHNUM:
130 			bootaux[BA_PHNUM].ba_val = auxv->a_un.a_val;
131 			break;
132 		case AT_PAGESZ:
133 			bootaux[BA_PAGESZ].ba_val = auxv->a_un.a_val;
134 			break;
135 		case AT_SUN_LDELF:
136 			bootaux[BA_LDELF].ba_ptr = auxv->a_un.a_ptr;
137 			break;
138 		case AT_SUN_LDSHDR:
139 			bootaux[BA_LDSHDR].ba_ptr = auxv->a_un.a_ptr;
140 			break;
141 		case AT_SUN_LDNAME:
142 			bootaux[BA_LDNAME].ba_ptr = auxv->a_un.a_ptr;
143 			break;
144 		case AT_SUN_LPAGESZ:
145 			bootaux[BA_LPAGESZ].ba_val = auxv->a_un.a_val;
146 			break;
147 		case AT_SUN_CPU:
148 			bootaux[BA_CPU].ba_ptr = auxv->a_un.a_ptr;
149 			break;
150 		case AT_SUN_MMU:
151 			bootaux[BA_MMU].ba_ptr = auxv->a_un.a_ptr;
152 			break;
153 		case AT_ENTRY:
154 			bootaux[BA_ENTRY].ba_ptr = auxv->a_un.a_ptr;
155 			break;
156 		default:
157 			break;
158 		}
159 	}
160 
161 	sh = (Shdr *)bootaux[BA_LDSHDR].ba_ptr;
162 	sh_num = ((Ehdr *)bootaux[BA_LDELF].ba_ptr)->e_shnum;
163 	/*
164 	 * Build cache table for section addresses.
165 	 */
166 	for (i = 0; i < sh_num; i++) {
167 		section[i] = sh++;
168 	}
169 
170 	/*
171 	 * Find the end of data
172 	 * (to allocate bss)
173 	 */
174 	phdr = (Phdr *)bootaux[BA_PHDR].ba_ptr;
175 	for (i = 0; i < bootaux[BA_PHNUM].ba_val; i++) {
176 		if (phdr->p_type == PT_LOAD &&
177 		    (phdr->p_flags & PF_W) && (phdr->p_flags & PF_X)) {
178 			edata = end = phdr->p_vaddr + phdr->p_memsz;
179 			break;
180 		}
181 		phdr = (Phdr *)((ulong_t)phdr + bootaux[BA_PHENT].ba_val);
182 	}
183 	if (edata == NULL)
184 		return;
185 
186 	/*
187 	 * Find the symbol table, and then loop
188 	 * through the symbols adjusting their
189 	 * values to reflect where the sections
190 	 * were loaded.
191 	 */
192 	for (i = 1; i < sh_num; i++) {
193 		Shdr *shp;
194 		Sym *sp;
195 		uint_t off;
196 
197 		shp = section[i];
198 		if (shp->sh_type != SHT_SYMTAB)
199 			continue;
200 
201 		for (off = 0; off < shp->sh_size; off += shp->sh_entsize) {
202 			sp = (Sym *)(shp->sh_addr + off);
203 
204 			if (sp->st_shndx == SHN_ABS ||
205 			    sp->st_shndx == SHN_UNDEF)
206 				continue;
207 			/*
208 			 * Assign the addresses for COMMON
209 			 * symbols even though we haven't
210 			 * actually allocated bss yet.
211 			 */
212 			if (sp->st_shndx == SHN_COMMON) {
213 				end = ALIGN(end, sp->st_value);
214 				sp->st_value = end;
215 				/*
216 				 * Squirrel it away for later.
217 				 */
218 				if (bootaux[BA_BSS].ba_val == 0)
219 					bootaux[BA_BSS].ba_val = end;
220 				end += sp->st_size;
221 				continue;
222 			} else if (sp->st_shndx > (Half)sh_num) {
223 				BSVC_PUTCHAR(syscallp, '>');
224 				return;
225 			}
226 
227 			/*
228 			 * Symbol's new address.
229 			 */
230 			sp->st_value += section[sp->st_shndx]->sh_addr;
231 		}
232 	}
233 
234 	/*
235 	 * Allocate bss for COMMON, if any.
236 	 */
237 	if (end > edata) {
238 		unsigned long va, bva;
239 		unsigned long asize;
240 		unsigned long align;
241 
242 		if (bootaux[BA_LPAGESZ].ba_val) {
243 			asize = bootaux[BA_LPAGESZ].ba_val;
244 			align = bootaux[BA_LPAGESZ].ba_val;
245 		} else {
246 			asize = bootaux[BA_PAGESZ].ba_val;
247 			align = BO_NO_ALIGN;
248 		}
249 		va = roundup(edata, asize);
250 		bva = roundup(end, asize);
251 
252 		if (bva > va) {
253 			bva = (unsigned long)BOP_ALLOC(bop, (caddr_t)va,
254 				bva - va, align);
255 			if (bva == NULL)
256 				return;
257 		}
258 		/*
259 		 * Zero it.
260 		 */
261 		for (va = edata; va < end; va++)
262 			*(char *)va = 0;
263 		/*
264 		 * Update the size of data.
265 		 */
266 		phdr->p_memsz += (end - edata);
267 	}
268 
269 	/*
270 	 * Relocate our own symbols.  We'll handle the
271 	 * undefined symbols later.
272 	 */
273 	for (i = 1; i < sh_num; i++) {
274 		Shdr *rshp, *shp, *ssp;
275 		unsigned long baseaddr, reladdr, rend;
276 		int relocsize;
277 
278 		rshp = section[i];
279 
280 		if (rshp->sh_type != SHT_REL)
281 			continue;
282 		/*
283 		 * Get the section being relocated
284 		 * and the symbol table.
285 		 */
286 		shp = section[rshp->sh_info];
287 		ssp = section[rshp->sh_link];
288 
289 		reladdr = rshp->sh_addr;
290 		baseaddr = shp->sh_addr;
291 		rend = reladdr + rshp->sh_size;
292 		relocsize = rshp->sh_entsize;
293 		/*
294 		 * Loop through relocations.
295 		 */
296 		while (reladdr < rend) {
297 			Sym *symref;
298 			Rel *reloc;
299 			unsigned long stndx;
300 			unsigned long off, *offptr;
301 			long value;
302 			int rtype;
303 
304 			reloc = (Rel *)reladdr;
305 			off = reloc->r_offset;
306 			rtype = ELF32_R_TYPE(reloc->r_info);
307 			stndx = ELF32_R_SYM(reloc->r_info);
308 
309 			reladdr += relocsize;
310 
311 			if (rtype == R_386_NONE) {
312 				continue;
313 			}
314 			off += baseaddr;
315 
316 			if (rtype == R_386_RELATIVE) {
317 				/*
318 				 * add base addr to reloc location
319 				 */
320 				value = baseaddr;
321 			} else {
322 				unsigned int symoff, symsize;
323 
324 				symsize = ssp->sh_entsize;
325 
326 				for (symoff = 0; stndx; stndx--)
327 					symoff += symsize;
328 				symref = (Sym *)(ssp->sh_addr + symoff);
329 
330 				/*
331 				 * Check for bad symbol index.
332 				 */
333 				if (symoff > ssp->sh_size)
334 					return;
335 
336 				/*
337 				 * Just bind our own symbols at this point.
338 				 */
339 				if (symref->st_shndx == SHN_UNDEF) {
340 					continue;
341 				}
342 
343 				value = symref->st_value;
344 				if (ELF32_ST_BIND(symref->st_info) !=
345 				    STB_LOCAL) {
346 					/*
347 					 * If PC-relative, subtract ref addr.
348 					 */
349 					if (rtype == R_386_PC32 ||
350 					    rtype == R_386_PLT32 ||
351 					    rtype == R_386_GOTPC)
352 						value -= off;
353 				}
354 			}
355 			offptr = (unsigned long *)off;
356 			/*
357 			 * insert value calculated at reference point
358 			 * 2 cases - normal byte order aligned, normal byte
359 			 * order unaligned.
360 			 */
361 			switch (rtype) {
362 			case R_386_PC32:
363 			case R_386_32:
364 			case R_386_PLT32:
365 			case R_386_RELATIVE:
366 				*offptr += value;
367 				break;
368 
369 			/*
370 			 * For now, ignore GOT references ...
371 			 */
372 
373 			case R_386_GOTPC:
374 #if defined(DEBUG) && !defined(__GNUC__)
375 				BSVC_PUTCHAR(syscallp, 'p');
376 #endif
377 				break;
378 			case R_386_GOTOFF:
379 				BSVC_PUTCHAR(syscallp, 'g');
380 				break;
381 			default:
382 				BSVC_PUTCHAR(syscallp, 'r');
383 				return;
384 			}
385 			/*
386 			 * We only need to do it once.
387 			 */
388 			reloc->r_info = ELF32_R_INFO(stndx, R_386_NONE);
389 		} /* while */
390 	}
391 
392 	/*
393 	 * Done relocating all of our *defined*
394 	 * symbols, so we hand off.
395 	 */
396 	kobj_init(syscallp, dvec, bootops, bootaux);
397 }
398