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