1 /* $NetBSD: loadfile_elf32.c,v 1.7 2002/02/11 20:25:56 reinoud Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center and by Christos Zoulas. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* If not included by exec_elf64.c, ELFSIZE won't be defined. */ 41 #ifndef ELFSIZE 42 #define ELFSIZE 32 43 #endif 44 45 #ifdef _STANDALONE 46 #include <lib/libsa/stand.h> 47 #include <lib/libkern/libkern.h> 48 #else 49 #include <stdio.h> 50 #include <string.h> 51 #include <errno.h> 52 #include <stdlib.h> 53 #include <unistd.h> 54 #include <fcntl.h> 55 #include <err.h> 56 #endif 57 58 #include <sys/param.h> 59 #include <sys/exec.h> 60 61 #include "loadfile.h" 62 63 #if ((ELFSIZE == 32) && defined(BOOT_ELF32)) || \ 64 ((ELFSIZE == 64) && defined(BOOT_ELF64)) 65 66 #define ELFROUND (ELFSIZE / 8) 67 68 #ifndef _STANDALONE 69 #include "byteorder.h" 70 71 /* 72 * Byte swapping may be necessary in the non-_STANDLONE case because 73 * we may be built with a host compiler. 74 */ 75 #define E16(f) \ 76 f = (bo == ELFDATA2LSB) ? sa_htole16(f) : sa_htobe16(f) 77 #define E32(f) \ 78 f = (bo == ELFDATA2LSB) ? sa_htole32(f) : sa_htobe32(f) 79 #define E64(f) \ 80 f = (bo == ELFDATA2LSB) ? sa_htole64(f) : sa_htobe64(f) 81 82 #define I16(f) \ 83 f = (bo == ELFDATA2LSB) ? sa_le16toh(f) : sa_be16toh(f) 84 #define I32(f) \ 85 f = (bo == ELFDATA2LSB) ? sa_le32toh(f) : sa_be32toh(f) 86 #define I64(f) \ 87 f = (bo == ELFDATA2LSB) ? sa_le64toh(f) : sa_be64toh(f) 88 89 static void 90 internalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr) 91 { 92 93 #if ELFSIZE == 32 94 I16(ehdr->e_type); 95 I16(ehdr->e_machine); 96 I32(ehdr->e_version); 97 I32(ehdr->e_entry); 98 I32(ehdr->e_phoff); 99 I32(ehdr->e_shoff); 100 I32(ehdr->e_flags); 101 I16(ehdr->e_ehsize); 102 I16(ehdr->e_phentsize); 103 I16(ehdr->e_phnum); 104 I16(ehdr->e_shentsize); 105 I16(ehdr->e_shnum); 106 I16(ehdr->e_shstrndx); 107 #elif ELFSIZE == 64 108 I16(ehdr->e_type); 109 I16(ehdr->e_machine); 110 I32(ehdr->e_version); 111 I64(ehdr->e_entry); 112 I64(ehdr->e_phoff); 113 I64(ehdr->e_shoff); 114 I32(ehdr->e_flags); 115 I16(ehdr->e_ehsize); 116 I16(ehdr->e_phentsize); 117 I16(ehdr->e_phnum); 118 I16(ehdr->e_shentsize); 119 I16(ehdr->e_shnum); 120 I16(ehdr->e_shstrndx); 121 #else 122 #error ELFSIZE is not 32 or 64 123 #endif 124 } 125 126 static void 127 externalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr) 128 { 129 130 #if ELFSIZE == 32 131 E16(ehdr->e_type); 132 E16(ehdr->e_machine); 133 E32(ehdr->e_version); 134 E32(ehdr->e_entry); 135 E32(ehdr->e_phoff); 136 E32(ehdr->e_shoff); 137 E32(ehdr->e_flags); 138 E16(ehdr->e_ehsize); 139 E16(ehdr->e_phentsize); 140 E16(ehdr->e_phnum); 141 E16(ehdr->e_shentsize); 142 E16(ehdr->e_shnum); 143 E16(ehdr->e_shstrndx); 144 #elif ELFSIZE == 64 145 E16(ehdr->e_type); 146 E16(ehdr->e_machine); 147 E32(ehdr->e_version); 148 E64(ehdr->e_entry); 149 E64(ehdr->e_phoff); 150 E64(ehdr->e_shoff); 151 E32(ehdr->e_flags); 152 E16(ehdr->e_ehsize); 153 E16(ehdr->e_phentsize); 154 E16(ehdr->e_phnum); 155 E16(ehdr->e_shentsize); 156 E16(ehdr->e_shnum); 157 E16(ehdr->e_shstrndx); 158 #else 159 #error ELFSIZE is not 32 or 64 160 #endif 161 } 162 163 static void 164 internalize_phdr(Elf_Byte bo, Elf_Phdr *phdr) 165 { 166 167 #if ELFSIZE == 32 168 I32(phdr->p_type); 169 I32(phdr->p_offset); 170 I32(phdr->p_vaddr); 171 I32(phdr->p_paddr); 172 I32(phdr->p_filesz); 173 I32(phdr->p_memsz); 174 I32(phdr->p_flags); 175 I32(phdr->p_align); 176 #elif ELFSIZE == 64 177 I32(phdr->p_type); 178 I32(phdr->p_offset); 179 I64(phdr->p_vaddr); 180 I64(phdr->p_paddr); 181 I64(phdr->p_filesz); 182 I64(phdr->p_memsz); 183 I64(phdr->p_flags); 184 I64(phdr->p_align); 185 #else 186 #error ELFSIZE is not 32 or 64 187 #endif 188 } 189 190 static void 191 internalize_shdr(Elf_Byte bo, Elf_Shdr *shdr) 192 { 193 194 #if ELFSIZE == 32 195 I32(shdr->sh_name); 196 I32(shdr->sh_type); 197 I32(shdr->sh_flags); 198 I32(shdr->sh_addr); 199 I32(shdr->sh_offset); 200 I32(shdr->sh_size); 201 I32(shdr->sh_link); 202 I32(shdr->sh_info); 203 I32(shdr->sh_addralign); 204 I32(shdr->sh_entsize); 205 #elif ELFSIZE == 64 206 I32(shdr->sh_name); 207 I32(shdr->sh_type); 208 I64(shdr->sh_flags); 209 I64(shdr->sh_addr); 210 I64(shdr->sh_offset); 211 I64(shdr->sh_size); 212 I32(shdr->sh_link); 213 I32(shdr->sh_info); 214 I64(shdr->sh_addralign); 215 I64(shdr->sh_entsize); 216 #else 217 #error ELFSIZE is not 32 or 64 218 #endif 219 } 220 221 static void 222 externalize_shdr(Elf_Byte bo, Elf_Shdr *shdr) 223 { 224 225 #if ELFSIZE == 32 226 E32(shdr->sh_name); 227 E32(shdr->sh_type); 228 E32(shdr->sh_flags); 229 E32(shdr->sh_addr); 230 E32(shdr->sh_offset); 231 E32(shdr->sh_size); 232 E32(shdr->sh_link); 233 E32(shdr->sh_info); 234 E32(shdr->sh_addralign); 235 E32(shdr->sh_entsize); 236 #elif ELFSIZE == 64 237 E32(shdr->sh_name); 238 E32(shdr->sh_type); 239 E64(shdr->sh_flags); 240 E64(shdr->sh_addr); 241 E64(shdr->sh_offset); 242 E64(shdr->sh_size); 243 E32(shdr->sh_link); 244 E32(shdr->sh_info); 245 E64(shdr->sh_addralign); 246 E64(shdr->sh_entsize); 247 #else 248 #error ELFSIZE is not 32 or 64 249 #endif 250 } 251 #else /* _STANDALONE */ 252 /* 253 * Byte swapping is never necessary in the _STANDALONE case because 254 * we are being built with the target compiler. 255 */ 256 #define internalize_ehdr(bo, ehdr) /* nothing */ 257 #define externalize_ehdr(bo, ehdr) /* nothing */ 258 259 #define internalize_phdr(bo, phdr) /* nothing */ 260 261 #define internalize_shdr(bo, shdr) /* nothing */ 262 #define externalize_shdr(bo, shdr) /* nothing */ 263 #endif /* _STANDALONE */ 264 265 int 266 ELFNAMEEND(loadfile)(fd, elf, marks, flags) 267 int fd; 268 Elf_Ehdr *elf; 269 u_long *marks; 270 int flags; 271 { 272 Elf_Shdr *shp; 273 Elf_Phdr *phdr; 274 int i, j; 275 size_t sz; 276 int first; 277 paddr_t minp = ~0, maxp = 0, pos = 0; 278 paddr_t offset = marks[MARK_START], shpp, elfp = NULL; 279 280 /* some ports dont use the offset */ 281 offset = offset; 282 283 internalize_ehdr(elf->e_ident[EI_DATA], elf); 284 285 sz = elf->e_phnum * sizeof(Elf_Phdr); 286 phdr = ALLOC(sz); 287 288 if (lseek(fd, elf->e_phoff, SEEK_SET) == -1) { 289 WARN(("lseek phdr")); 290 FREE(phdr, sz); 291 return 1; 292 } 293 if (read(fd, phdr, sz) != sz) { 294 WARN(("read program headers")); 295 FREE(phdr, sz); 296 return 1; 297 } 298 299 for (first = 1, i = 0; i < elf->e_phnum; i++) { 300 internalize_phdr(elf->e_ident[EI_DATA], &phdr[i]); 301 if (phdr[i].p_type != PT_LOAD || 302 (phdr[i].p_flags & (PF_W|PF_X)) == 0) 303 continue; 304 305 #define IS_TEXT(p) (p.p_flags & PF_X) 306 #define IS_DATA(p) (p.p_flags & PF_W) 307 #define IS_BSS(p) (p.p_filesz < p.p_memsz) 308 /* 309 * XXX: Assume first address is lowest 310 */ 311 if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) || 312 (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) { 313 314 /* Read in segment. */ 315 PROGRESS(("%s%lu", first ? "" : "+", 316 (u_long)phdr[i].p_filesz)); 317 318 if (lseek(fd, phdr[i].p_offset, SEEK_SET) == -1) { 319 WARN(("lseek text")); 320 FREE(phdr, sz); 321 return 1; 322 } 323 if (READ(fd, phdr[i].p_vaddr, phdr[i].p_filesz) != 324 phdr[i].p_filesz) { 325 WARN(("read text")); 326 FREE(phdr, sz); 327 return 1; 328 } 329 first = 0; 330 331 } 332 if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT|COUNT_TEXT))) || 333 (IS_DATA(phdr[i]) && (flags & (LOAD_DATA|COUNT_TEXT)))) { 334 pos = phdr[i].p_vaddr; 335 if (minp > pos) 336 minp = pos; 337 pos += phdr[i].p_filesz; 338 if (maxp < pos) 339 maxp = pos; 340 } 341 342 /* Zero out bss. */ 343 if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) { 344 PROGRESS(("+%lu", 345 (u_long)(phdr[i].p_memsz - phdr[i].p_filesz))); 346 BZERO((phdr[i].p_vaddr + phdr[i].p_filesz), 347 phdr[i].p_memsz - phdr[i].p_filesz); 348 } 349 if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) { 350 pos += phdr[i].p_memsz - phdr[i].p_filesz; 351 if (maxp < pos) 352 maxp = pos; 353 } 354 } 355 FREE(phdr, sz); 356 357 /* 358 * Copy the ELF and section headers. 359 */ 360 maxp = roundup(maxp, ELFROUND); 361 if (flags & (LOAD_HDR|COUNT_HDR)) { 362 elfp = maxp; 363 maxp += sizeof(Elf_Ehdr); 364 } 365 366 if (flags & (LOAD_SYM|COUNT_SYM)) { 367 if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) { 368 WARN(("lseek section headers")); 369 return 1; 370 } 371 sz = elf->e_shnum * sizeof(Elf_Shdr); 372 373 shp = ALLOC(sz); 374 375 if (read(fd, shp, sz) != sz) { 376 WARN(("read section headers")); 377 return 1; 378 } 379 380 shpp = maxp; 381 maxp += roundup(sz, ELFROUND); 382 383 #ifndef _STANDALONE 384 /* Internalize the section headers. */ 385 for (i = 0; i < elf->e_shnum; i++) 386 internalize_shdr(elf->e_ident[EI_DATA], &shp[i]); 387 #endif /* ! _STANDALONE */ 388 389 /* 390 * Now load the symbol sections themselves. Make sure 391 * the sections are aligned. Don't bother with any 392 * string table that isn't referenced by a symbol 393 * table. 394 */ 395 for (first = 1, i = 0; i < elf->e_shnum; i++) { 396 switch (shp[i].sh_type) { 397 case SHT_STRTAB: 398 for (j = 0; j < elf->e_shnum; j++) 399 if (shp[j].sh_type == SHT_SYMTAB && 400 shp[j].sh_link == i) 401 goto havesym; 402 /* FALLTHROUGH */ 403 default: 404 /* Not loading this, so zero out the offset. */ 405 shp[i].sh_offset = 0; 406 break; 407 havesym: 408 case SHT_SYMTAB: 409 if (flags & LOAD_SYM) { 410 PROGRESS(("%s%ld", first ? " [" : "+", 411 (u_long)shp[i].sh_size)); 412 if (lseek(fd, shp[i].sh_offset, 413 SEEK_SET) == -1) { 414 WARN(("lseek symbols")); 415 FREE(shp, sz); 416 return 1; 417 } 418 if (READ(fd, maxp, shp[i].sh_size) != 419 shp[i].sh_size) { 420 WARN(("read symbols")); 421 FREE(shp, sz); 422 return 1; 423 } 424 } 425 shp[i].sh_offset = maxp - elfp; 426 maxp += roundup(shp[i].sh_size, ELFROUND); 427 first = 0; 428 } 429 /* Since we don't load .shstrtab, zero the name. */ 430 shp[i].sh_name = 0; 431 } 432 if (flags & LOAD_SYM) { 433 #ifndef _STANDALONE 434 /* Externalize the section headers. */ 435 for (i = 0; i < elf->e_shnum; i++) 436 externalize_shdr(elf->e_ident[EI_DATA], 437 &shp[i]); 438 #endif /* ! _STANDALONE */ 439 BCOPY(shp, shpp, sz); 440 441 if (first == 0) 442 PROGRESS(("]")); 443 } 444 FREE(shp, sz); 445 } 446 447 /* 448 * Frob the copied ELF header to give information relative 449 * to elfp. 450 */ 451 if (flags & LOAD_HDR) { 452 elf->e_phoff = 0; 453 elf->e_shoff = sizeof(Elf_Ehdr); 454 elf->e_phentsize = 0; 455 elf->e_phnum = 0; 456 elf->e_shstrndx = SHN_UNDEF; 457 externalize_ehdr(elf->e_ident[EI_DATA], elf); 458 BCOPY(elf, elfp, sizeof(*elf)); 459 internalize_ehdr(elf->e_ident[EI_DATA], elf); 460 } 461 462 marks[MARK_START] = LOADADDR(minp); 463 marks[MARK_ENTRY] = LOADADDR(elf->e_entry); 464 /* 465 * Since there can be more than one symbol section in the code 466 * and we need to find strtab too in order to do anything 467 * useful with the symbols, we just pass the whole elf 468 * header back and we let the kernel debugger find the 469 * location and number of symbols by itself. 470 */ 471 marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */ 472 marks[MARK_SYM] = LOADADDR(elfp); 473 marks[MARK_END] = LOADADDR(maxp); 474 return 0; 475 } 476 477 #endif /* (ELFSIZE == 32 && BOOT_ELF32) || (ELFSIZE == 64 && BOOT_ELF64) */ 478