xref: /titanic_44/usr/src/uts/intel/amd64/krtld/kobj_boot.c (revision 28167c24ba5be8b7c1d05e02d053f4a55cd21cc9)
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 #if !defined(_KERNEL)
49 #pragma weak _GLOBAL_OFFSET_TABLE_
50 #endif
51 
52 #else
53 
54 /*
55  * We -do- use the global offset table, but only by
56  * accident -- when you tell gcc to emit PIC code,
57  * it -always- generates a reference to the GOT in
58  * a register, even if the compilation unit never
59  * uses it.
60  *
61  * Rumoured to be fixed in a later version of gcc..
62  */
63 
64 long	_GLOBAL_OFFSET_TABLE_[1];
65 
66 #endif
67 
68 #define	roundup		ALIGN
69 
70 #define	MAXSECT		64	/* max # of sects. */
71 
72 #define	HIBITS		0xffffffff80000000	/* upper 32 bits */
73 
74 /*
75  * Boot transfers control here. At this point,
76  * we haven't relocated our own symbols, so the
77  * world (as we know it) is pretty small right now.
78  */
79 void
80 _kobj_boot(
81 	struct boot_syscalls *syscallp,
82 	void *dvec,
83 	struct bootops *bootops,
84 	Boot *ebp)
85 {
86 	Shdr *section[MAXSECT];	/* cache */
87 	val_t bootaux[BA_NUM];
88 	struct bootops *bop;
89 	Phdr *phdr;
90 	auxv_t *auxv = NULL;
91 	Shdr *sh;
92 	Half sh_num;
93 	ulong_t end, edata = 0;
94 	int i;
95 
96 	bop = (dvec) ? *(struct bootops **)bootops : bootops;
97 
98 	for (i = 0; i < BA_NUM; i++)
99 		bootaux[i].ba_val = NULL;
100 
101 	/*
102 	 * Check the bootstrap vector.
103 	 */
104 	for (; ebp->eb_tag != EB_NULL; ebp++) {
105 		switch (ebp->eb_tag) {
106 		case EB_AUXV:
107 			auxv = (auxv_t *)ebp->eb_un.eb_ptr;
108 			break;
109 		case EB_DYNAMIC:
110 			bootaux[BA_DYNAMIC].ba_ptr = (void *)ebp->eb_un.eb_ptr;
111 			break;
112 		default:
113 			break;
114 		}
115 	}
116 
117 	if (auxv == NULL)
118 		return;
119 
120 	/*
121 	 * Now the aux vector.
122 	 */
123 	for (; auxv->a_type != AT_NULL; auxv++) {
124 		switch (auxv->a_type) {
125 		case AT_PHDR:
126 			bootaux[BA_PHDR].ba_ptr = auxv->a_un.a_ptr;
127 			break;
128 		case AT_PHENT:
129 			bootaux[BA_PHENT].ba_val = auxv->a_un.a_val;
130 			break;
131 		case AT_PHNUM:
132 			bootaux[BA_PHNUM].ba_val = auxv->a_un.a_val;
133 			break;
134 		case AT_PAGESZ:
135 			bootaux[BA_PAGESZ].ba_val = auxv->a_un.a_val;
136 			break;
137 		case AT_SUN_LDELF:
138 			bootaux[BA_LDELF].ba_ptr = auxv->a_un.a_ptr;
139 			break;
140 		case AT_SUN_LDSHDR:
141 			bootaux[BA_LDSHDR].ba_ptr = auxv->a_un.a_ptr;
142 			break;
143 		case AT_SUN_LDNAME:
144 			bootaux[BA_LDNAME].ba_ptr = auxv->a_un.a_ptr;
145 			break;
146 		case AT_SUN_LPAGESZ:
147 			bootaux[BA_LPAGESZ].ba_val = auxv->a_un.a_val;
148 			break;
149 		case AT_SUN_CPU:
150 			bootaux[BA_CPU].ba_ptr = auxv->a_un.a_ptr;
151 			break;
152 		case AT_SUN_MMU:
153 			bootaux[BA_MMU].ba_ptr = auxv->a_un.a_ptr;
154 			break;
155 		case AT_ENTRY:
156 			bootaux[BA_ENTRY].ba_ptr = auxv->a_un.a_ptr;
157 			break;
158 		default:
159 			break;
160 		}
161 	}
162 
163 
164 	sh = (Shdr *)bootaux[BA_LDSHDR].ba_ptr;
165 	sh_num = ((Ehdr *)bootaux[BA_LDELF].ba_ptr)->e_shnum;
166 	/*
167 	 * Make sure we won't overflow stack allocated cache
168 	 */
169 	if (sh_num >= MAXSECT)
170 		return;
171 
172 	/*
173 	 * Build cache table for section addresses.
174 	 */
175 	for (i = 0; i < sh_num; i++) {
176 		section[i] = sh++;
177 	}
178 
179 	/*
180 	 * Find the end of data
181 	 * (to allocate bss)
182 	 */
183 	phdr = (Phdr *)bootaux[BA_PHDR].ba_ptr;
184 
185 	for (i = 0; i < bootaux[BA_PHNUM].ba_val; i++) {
186 		if (phdr->p_type == PT_LOAD &&
187 		    (phdr->p_flags & PF_W) && (phdr->p_flags & PF_X)) {
188 			edata = end = phdr->p_vaddr + phdr->p_memsz;
189 			break;
190 		}
191 		phdr = (Phdr *)((ulong_t)phdr + bootaux[BA_PHENT].ba_val);
192 	}
193 	if (edata == NULL)
194 		return;
195 
196 	/*
197 	 * Find the symbol table, and then loop
198 	 * through the symbols adjusting their
199 	 * values to reflect where the sections
200 	 * were loaded.
201 	 */
202 	for (i = 1; i < sh_num; i++) {
203 		Shdr *shp;
204 		Sym *sp;
205 		ulong_t off;
206 
207 		shp = section[i];
208 		if (shp->sh_type != SHT_SYMTAB)
209 			continue;
210 
211 		for (off = 0; off < shp->sh_size; off += shp->sh_entsize) {
212 			sp = (Sym *)(shp->sh_addr + off);
213 
214 			if (sp->st_shndx == SHN_ABS ||
215 			    sp->st_shndx == SHN_UNDEF)
216 				continue;
217 
218 			/*
219 			 * Assign the addresses for COMMON
220 			 * symbols even though we haven't
221 			 * actually allocated bss yet.
222 			 */
223 			if (sp->st_shndx == SHN_COMMON) {
224 				end = ALIGN(end, sp->st_value);
225 				sp->st_value = end;
226 				/*
227 				 * Squirrel it away for later.
228 				 */
229 				if (bootaux[BA_BSS].ba_val == 0)
230 					bootaux[BA_BSS].ba_val = end;
231 				end += sp->st_size;
232 				continue;
233 			} else if (sp->st_shndx > (Half)sh_num) {
234 				BSVC_PUTCHAR(syscallp, '>');
235 				return;
236 			}
237 
238 			/*
239 			 * Symbol's new address.
240 			 */
241 			sp->st_value += section[sp->st_shndx]->sh_addr;
242 		}
243 	}
244 
245 	/*
246 	 * Allocate bss for COMMON, if any.
247 	 */
248 	if (end > edata) {
249 		unsigned long va, bva;
250 		unsigned long asize;
251 		unsigned long align;
252 
253 		if (bootaux[BA_LPAGESZ].ba_val) {
254 			asize = bootaux[BA_LPAGESZ].ba_val;
255 			align = bootaux[BA_LPAGESZ].ba_val;
256 		} else {
257 			asize = bootaux[BA_PAGESZ].ba_val;
258 			align = BO_NO_ALIGN;
259 		}
260 		va = roundup(edata, asize);
261 		bva = roundup(end, asize);
262 
263 		if (bva > va) {
264 			bva = (unsigned long)BOP_ALLOC(bop, (caddr_t)va,
265 				bva - va, align);
266 			if (bva == NULL)
267 				return;
268 		}
269 		/*
270 		 * Zero it.
271 		 */
272 		for (va = edata; va < end; va++)
273 			*(char *)va = 0;
274 		/*
275 		 * Update the size of data.
276 		 */
277 		phdr->p_memsz += (end - edata);
278 	}
279 
280 	/*
281 	 * Relocate our own symbols.  We'll handle the
282 	 * undefined symbols later.
283 	 */
284 	for (i = 1; i < sh_num; i++) {
285 		Shdr *rshp, *shp, *ssp;
286 		unsigned long baseaddr, reladdr, rend;
287 		long relocsize;
288 
289 		rshp = section[i];
290 
291 		if (rshp->sh_type != SHT_RELA)
292 			continue;
293 		/*
294 		 * Get the section being relocated
295 		 * and the symbol table.
296 		 */
297 		shp = section[rshp->sh_info];
298 		ssp = section[rshp->sh_link];
299 
300 		/*
301 		 * Only perform relocations against allocatable
302 		 * sections.
303 		 */
304 		if ((shp->sh_flags & SHF_ALLOC) == 0)
305 			continue;
306 
307 		reladdr = rshp->sh_addr;
308 		baseaddr = shp->sh_addr;
309 		rend = reladdr + rshp->sh_size;
310 		relocsize = rshp->sh_entsize;
311 		/*
312 		 * Loop through relocations.
313 		 */
314 
315 		while (reladdr < rend) {
316 			Sym *symref;
317 			Rela *reloc;
318 			unsigned long stndx;
319 			unsigned long off, *offptr;
320 			long addend, value;
321 			unsigned long symoff, symsize;
322 			int rtype;
323 
324 			reloc = (Rela *)reladdr;
325 			off = reloc->r_offset;
326 			addend = (long)reloc->r_addend;
327 			rtype = ELF_R_TYPE(reloc->r_info);
328 			stndx = ELF_R_SYM(reloc->r_info);
329 
330 			reladdr += relocsize;
331 
332 			if (rtype == R_AMD64_NONE)
333 				continue;
334 
335 			off += baseaddr;
336 
337 			symsize = ssp->sh_entsize;
338 			symoff = stndx * symsize;
339 
340 			/*
341 			 * Check for bad symbol index.
342 			 */
343 			if (symoff > ssp->sh_size)
344 				return;
345 
346 			symref = (Sym *)(ssp->sh_addr + symoff);
347 
348 
349 			/*
350 			 * Just bind our own symbols at this point.
351 			 */
352 			if (symref->st_shndx == SHN_UNDEF)
353 				continue;
354 
355 			value = symref->st_value;
356 
357 			if ((rtype == R_AMD64_PC32) ||
358 			    (rtype == R_AMD64_PLT32))
359 				/*
360 				 * If PC-relative, subtract ref addr.
361 				 */
362 				value -= off;
363 			else if (rtype == R_AMD64_32) {
364 				/*
365 				 * It's illegal to have any HIBITS
366 				 * set for R_AMD64_32 reloc.
367 				 */
368 				if (value & HIBITS) {
369 					BSVC_PUTCHAR(syscallp, 'h');
370 					return;
371 				}
372 			} else if (rtype == R_AMD64_32S) {
373 				/*
374 				 * All HIBITS for R_AMD64_32S
375 				 * *must* be set.
376 				 */
377 				if ((value & HIBITS) != HIBITS) {
378 					BSVC_PUTCHAR(syscallp, 'H');
379 					return;
380 				}
381 			}
382 
383 			offptr = (unsigned long *)off;
384 			/*
385 			 * insert value calculated at reference point
386 			 * 2 cases - normal byte order aligned, normal byte
387 			 * order unaligned.
388 			 */
389 			switch (rtype) {
390 			case R_AMD64_64:
391 				*(unsigned long *)offptr = value + addend;
392 				break;
393 			case R_AMD64_PC32:
394 			case R_AMD64_32S:
395 			case R_AMD64_PLT32:
396 				*(uint_t *)offptr = (uint_t)(value + addend);
397 				break;
398 			case R_AMD64_GOT32:
399 				BSVC_PUTCHAR(syscallp, 'G');
400 				return;
401 			case R_AMD64_32:
402 				return;
403 			default:
404 				BSVC_PUTCHAR(syscallp, 'R');
405 				return;
406 			}
407 			/*
408 			 * We only need to do it once.
409 			 */
410 			reloc->r_info = ELF_R_INFO(stndx, R_AMD64_NONE);
411 		} /* while */
412 	}
413 
414 	/*
415 	 * Done relocating all of our *defined*
416 	 * symbols, so we hand off.
417 	 */
418 	kobj_init(syscallp, dvec, bootops, bootaux);
419 }
420