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