1 /*- 2 * Copyright (c) 1995-1996 S�ren Schmidt 3 * Copyright (c) 1996 Peter Wemm 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer 11 * in this position and unchanged. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software withough specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $Id: imgact_elf.c,v 1.29 1998/07/29 18:39:35 dfr Exp $ 30 */ 31 32 #include "opt_rlimit.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/exec.h> 37 #include <sys/mman.h> 38 #include <sys/imgact.h> 39 #include <sys/imgact_elf.h> 40 #include <sys/kernel.h> 41 #include <sys/sysent.h> 42 #include <sys/malloc.h> 43 #include <sys/namei.h> 44 #include <sys/proc.h> 45 #include <sys/syscall.h> 46 #include <sys/signalvar.h> 47 #include <sys/sysctl.h> 48 #include <sys/vnode.h> 49 50 #include <vm/vm.h> 51 #include <vm/vm_kern.h> 52 #include <vm/vm_param.h> 53 #include <vm/pmap.h> 54 #include <sys/lock.h> 55 #include <vm/vm_map.h> 56 #include <vm/vm_prot.h> 57 #include <vm/vm_extern.h> 58 59 #include <machine/md_var.h> 60 61 #define MAX_PHDR 32 /* XXX enough ? */ 62 63 #if ELF_TARG_CLASS == ELFCLASS32 64 65 #define Elf_Ehdr Elf32_Ehdr 66 #define Elf_Phdr Elf32_Phdr 67 #define Elf_Auxargs Elf32_Auxargs 68 #define Elf_Brandinfo Elf32_Brandinfo 69 70 #else 71 72 #define Elf_Ehdr Elf64_Ehdr 73 #define Elf_Phdr Elf64_Phdr 74 #define Elf_Auxargs Elf64_Auxargs 75 #define Elf_Brandinfo Elf64_Brandinfo 76 77 #endif 78 79 80 static int elf_check_header __P((const Elf_Ehdr *hdr, int type)); 81 static int elf_load_section __P((struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot)); 82 static int elf_load_file __P((struct proc *p, char *file, u_long *addr, u_long *entry)); 83 static int elf_freebsd_fixup __P((long **stack_base, struct image_params *imgp)); 84 static int exec_elf_imgact __P((struct image_params *imgp)); 85 86 static int elf_trace = 0; 87 SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); 88 #define UPRINTF if (elf_trace) uprintf 89 90 static struct sysentvec elf_freebsd_sysvec = { 91 SYS_MAXSYSCALL, 92 sysent, 93 0, 94 0, 95 0, 96 0, 97 0, 98 0, 99 elf_freebsd_fixup, 100 sendsig, 101 sigcode, 102 &szsigcode, 103 0, 104 "FreeBSD ELF", 105 elf_coredump 106 }; 107 108 static Elf_Brandinfo freebsd_brand_info = { 109 "FreeBSD", 110 "", 111 "/usr/libexec/ld-elf.so.1", 112 &elf_freebsd_sysvec 113 }; 114 static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = { 115 &freebsd_brand_info, 116 NULL, NULL, NULL, 117 NULL, NULL, NULL, NULL 118 }; 119 120 int 121 elf_insert_brand_entry(Elf_Brandinfo *entry) 122 { 123 int i; 124 125 for (i=1; i<MAX_BRANDS; i++) { 126 if (elf_brand_list[i] == NULL) { 127 elf_brand_list[i] = entry; 128 break; 129 } 130 } 131 if (i == MAX_BRANDS) 132 return -1; 133 return 0; 134 } 135 136 int 137 elf_remove_brand_entry(Elf_Brandinfo *entry) 138 { 139 int i; 140 141 for (i=1; i<MAX_BRANDS; i++) { 142 if (elf_brand_list[i] == entry) { 143 elf_brand_list[i] = NULL; 144 break; 145 } 146 } 147 if (i == MAX_BRANDS) 148 return -1; 149 return 0; 150 } 151 152 static int 153 elf_check_header(const Elf_Ehdr *hdr, int type) 154 { 155 if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 && 156 hdr->e_ident[EI_MAG1] == ELFMAG1 && 157 hdr->e_ident[EI_MAG2] == ELFMAG2 && 158 hdr->e_ident[EI_MAG3] == ELFMAG3)) 159 return ENOEXEC; 160 161 #ifdef __i386__ 162 if (hdr->e_machine != EM_386 && hdr->e_machine != EM_486) 163 #endif 164 #ifdef __alpha__ 165 if (hdr->e_machine != EM_ALPHA) 166 #endif 167 return ENOEXEC; 168 169 170 if (hdr->e_type != type) 171 return ENOEXEC; 172 173 return 0; 174 } 175 176 static int 177 elf_load_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot) 178 { 179 size_t map_len; 180 vm_offset_t map_addr; 181 int error; 182 unsigned char *data_buf = 0; 183 size_t copy_len; 184 185 map_addr = trunc_page(vmaddr); 186 187 if (memsz > filsz) 188 map_len = trunc_page(offset+filsz) - trunc_page(offset); 189 else 190 map_len = round_page(offset+filsz) - trunc_page(offset); 191 192 if (error = vm_mmap (&vmspace->vm_map, 193 &map_addr, 194 map_len, 195 prot, 196 VM_PROT_ALL, 197 MAP_PRIVATE | MAP_FIXED, 198 (caddr_t)vp, 199 trunc_page(offset))) 200 return error; 201 202 if (memsz == filsz) 203 return 0; 204 205 /* 206 * We have to map the remaining bit of the file into the kernel's 207 * memory map, allocate some anonymous memory, and copy that last 208 * bit into it. The remaining space should be .bss... 209 */ 210 copy_len = (offset + filsz) - trunc_page(offset + filsz); 211 map_addr = trunc_page(vmaddr + filsz); 212 map_len = round_page(vmaddr + memsz) - map_addr; 213 214 if (map_len != 0) { 215 if (error = vm_map_find(&vmspace->vm_map, NULL, 0, 216 &map_addr, map_len, FALSE, 217 VM_PROT_ALL, VM_PROT_ALL,0)) 218 return error; 219 } 220 221 if (error = vm_mmap(exec_map, 222 (vm_offset_t *)&data_buf, 223 PAGE_SIZE, 224 VM_PROT_READ, 225 VM_PROT_READ, 226 0, 227 (caddr_t)vp, 228 trunc_page(offset + filsz))) 229 return error; 230 231 error = copyout(data_buf, (caddr_t)map_addr, copy_len); 232 233 vm_map_remove(exec_map, (vm_offset_t)data_buf, 234 (vm_offset_t)data_buf + PAGE_SIZE); 235 236 /* 237 * set it to the specified protection 238 */ 239 vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, 240 FALSE); 241 242 UPRINTF("bss size %d (%x)\n", map_len-copy_len, map_len-copy_len); 243 return error; 244 } 245 246 static int 247 elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) 248 { 249 Elf_Ehdr *hdr = NULL; 250 Elf_Phdr *phdr = NULL; 251 struct nameidata nd; 252 struct vmspace *vmspace = p->p_vmspace; 253 struct vattr attr; 254 struct image_params image_params, *imgp; 255 vm_prot_t prot = 0; 256 unsigned long text_size = 0, data_size = 0; 257 unsigned long text_addr = 0, data_addr = 0; 258 int header_size = 0; 259 int error, i; 260 261 imgp = &image_params; 262 /* 263 * Initialize part of the common data 264 */ 265 imgp->proc = p; 266 imgp->uap = NULL; 267 imgp->attr = &attr; 268 imgp->firstpage = NULL; 269 imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE); 270 271 if (imgp->image_header == NULL) { 272 nd.ni_vp = NULL; 273 error = ENOMEM; 274 goto fail; 275 } 276 277 NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p); 278 279 if (error = namei(&nd)) { 280 nd.ni_vp = NULL; 281 goto fail; 282 } 283 284 imgp->vp = nd.ni_vp; 285 286 /* 287 * Check permissions, modes, uid, etc on the file, and "open" it. 288 */ 289 error = exec_check_permissions(imgp); 290 if (error) { 291 VOP_UNLOCK(nd.ni_vp, 0, p); 292 goto fail; 293 } 294 295 error = exec_map_first_page(imgp); 296 VOP_UNLOCK(nd.ni_vp, 0, p); 297 if (error) 298 goto fail; 299 300 hdr = (Elf_Ehdr *)imgp->image_header; 301 if (error = elf_check_header(hdr, ET_DYN)) 302 goto fail; 303 304 /* 305 * ouch, need to bounds check in case user gives us a corrupted 306 * file with an insane header size 307 */ 308 if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ 309 error = ENOEXEC; 310 goto fail; 311 } 312 313 header_size = hdr->e_phentsize * hdr->e_phnum; 314 315 /* Only support headers that fit within first page for now */ 316 if (header_size + hdr->e_phoff > PAGE_SIZE) { 317 error = ENOEXEC; 318 goto fail; 319 } 320 321 phdr = (Elf_Phdr *)(imgp->image_header + hdr->e_phoff); 322 323 for (i = 0; i < hdr->e_phnum; i++) { 324 switch(phdr[i].p_type) { 325 326 case PT_NULL: /* NULL section */ 327 UPRINTF ("ELF(file) PT_NULL section\n"); 328 break; 329 case PT_LOAD: /* Loadable segment */ 330 { 331 UPRINTF ("ELF(file) PT_LOAD section "); 332 if (phdr[i].p_flags & PF_X) 333 prot |= VM_PROT_EXECUTE; 334 if (phdr[i].p_flags & PF_W) 335 prot |= VM_PROT_WRITE; 336 if (phdr[i].p_flags & PF_R) 337 prot |= VM_PROT_READ; 338 339 if (error = elf_load_section(vmspace, nd.ni_vp, 340 phdr[i].p_offset, 341 (caddr_t)phdr[i].p_vaddr + 342 (*addr), 343 phdr[i].p_memsz, 344 phdr[i].p_filesz, prot)) 345 goto fail; 346 347 /* 348 * Is this .text or .data ?? 349 * 350 * We only handle one each of those yet XXX 351 */ 352 if (hdr->e_entry >= phdr[i].p_vaddr && 353 hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 354 text_addr = trunc_page(phdr[i].p_vaddr+(*addr)); 355 text_size = round_page(phdr[i].p_memsz + 356 phdr[i].p_vaddr - 357 trunc_page(phdr[i].p_vaddr)); 358 *entry=(unsigned long)hdr->e_entry+(*addr); 359 UPRINTF(".text <%08lx,%08lx> entry=%08lx\n", 360 text_addr, text_size, *entry); 361 } else { 362 data_addr = trunc_page(phdr[i].p_vaddr+(*addr)); 363 data_size = round_page(phdr[i].p_memsz + 364 phdr[i].p_vaddr - 365 trunc_page(phdr[i].p_vaddr)); 366 UPRINTF(".data <%08lx,%08lx>\n", 367 data_addr, data_size); 368 } 369 } 370 break; 371 372 case PT_DYNAMIC:/* Dynamic link information */ 373 UPRINTF ("ELF(file) PT_DYNAMIC section\n"); 374 break; 375 case PT_INTERP: /* Path to interpreter */ 376 UPRINTF ("ELF(file) PT_INTERP section\n"); 377 break; 378 case PT_NOTE: /* Note section */ 379 UPRINTF ("ELF(file) PT_NOTE section\n"); 380 break; 381 case PT_SHLIB: /* Shared lib section */ 382 UPRINTF ("ELF(file) PT_SHLIB section\n"); 383 break; 384 case PT_PHDR: /* Program header table info */ 385 UPRINTF ("ELF(file) PT_PHDR section\n"); 386 break; 387 default: 388 UPRINTF ("ELF(file) %d section ??\n", phdr[i].p_type ); 389 } 390 } 391 392 fail: 393 if (imgp->firstpage) 394 exec_unmap_first_page(imgp); 395 if (imgp->image_header) 396 kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header, 397 PAGE_SIZE); 398 if (nd.ni_vp) 399 vrele(nd.ni_vp); 400 401 return error; 402 } 403 404 static int 405 exec_elf_imgact(struct image_params *imgp) 406 { 407 const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header; 408 const Elf_Phdr *phdr, *mapped_phdr = NULL; 409 Elf_Auxargs *elf_auxargs = NULL; 410 struct vmspace *vmspace; 411 vm_prot_t prot = 0; 412 u_long text_size = 0, data_size = 0; 413 u_long text_addr = 0, data_addr = 0; 414 u_long addr, entry = 0, proghdr = 0; 415 int error, i, header_size = 0; 416 const char *interp = NULL; 417 char *brand = NULL; 418 char path[MAXPATHLEN]; 419 420 /* 421 * Do we have a valid ELF header ? 422 */ 423 if (elf_check_header(hdr, ET_EXEC)) 424 return -1; 425 426 /* 427 * From here on down, we return an errno, not -1, as we've 428 * detected an ELF file. 429 */ 430 431 /* 432 * ouch, need to bounds check in case user gives us a corrupted 433 * file with an insane header size 434 */ 435 if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ 436 return ENOEXEC; 437 } 438 439 header_size = hdr->e_phentsize * hdr->e_phnum; 440 441 if ((hdr->e_phoff > PAGE_SIZE) || 442 (hdr->e_phoff + header_size) > PAGE_SIZE) { 443 /* Only support headers in first page for now */ 444 return ENOEXEC; 445 } else { 446 phdr = (const Elf_Phdr*) 447 ((const char *)imgp->image_header + hdr->e_phoff); 448 } 449 450 /* 451 * From this point on, we may have resources that need to be freed. 452 */ 453 if (error = exec_extract_strings(imgp)) 454 goto fail; 455 456 exec_new_vmspace(imgp); 457 458 vmspace = imgp->proc->p_vmspace; 459 460 for (i = 0; i < hdr->e_phnum; i++) { 461 switch(phdr[i].p_type) { 462 463 case PT_NULL: /* NULL section */ 464 UPRINTF ("ELF PT_NULL section\n"); 465 break; 466 case PT_LOAD: /* Loadable segment */ 467 { 468 UPRINTF ("ELF PT_LOAD section "); 469 if (phdr[i].p_flags & PF_X) 470 prot |= VM_PROT_EXECUTE; 471 if (phdr[i].p_flags & PF_W) 472 prot |= VM_PROT_WRITE; 473 if (phdr[i].p_flags & PF_R) 474 prot |= VM_PROT_READ; 475 476 if (error = elf_load_section(vmspace, imgp->vp, 477 phdr[i].p_offset, 478 (caddr_t)phdr[i].p_vaddr, 479 phdr[i].p_memsz, 480 phdr[i].p_filesz, prot)) 481 goto fail; 482 483 /* 484 * Is this .text or .data ?? 485 * 486 * We only handle one each of those yet XXX 487 */ 488 if (hdr->e_entry >= phdr[i].p_vaddr && 489 hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 490 text_addr = trunc_page(phdr[i].p_vaddr); 491 text_size = round_page(phdr[i].p_memsz + 492 phdr[i].p_vaddr - 493 text_addr); 494 entry = (u_long)hdr->e_entry; 495 UPRINTF(".text <%08lx,%08lx> entry=%08lx\n", 496 text_addr, text_size, entry); 497 } else { 498 data_addr = trunc_page(phdr[i].p_vaddr); 499 data_size = round_page(phdr[i].p_memsz + 500 phdr[i].p_vaddr - 501 data_addr); 502 UPRINTF(".data <%08lx,%08lx>\n", 503 data_addr, data_size); 504 } 505 } 506 break; 507 508 case PT_DYNAMIC:/* Dynamic link information */ 509 UPRINTF ("ELF PT_DYNAMIC section ??\n"); 510 break; 511 case PT_INTERP: /* Path to interpreter */ 512 UPRINTF ("ELF PT_INTERP section "); 513 if (phdr[i].p_filesz > MAXPATHLEN || 514 phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) { 515 error = ENOEXEC; 516 goto fail; 517 } 518 interp = imgp->image_header + phdr[i].p_offset; 519 UPRINTF("<%s>\n", interp); 520 break; 521 case PT_NOTE: /* Note section */ 522 UPRINTF ("ELF PT_NOTE section\n"); 523 break; 524 case PT_SHLIB: /* Shared lib section */ 525 UPRINTF ("ELF PT_SHLIB section\n"); 526 break; 527 case PT_PHDR: /* Program header table info */ 528 UPRINTF ("ELF PT_PHDR section <%x>\n", phdr[i].p_vaddr); 529 proghdr = phdr[i].p_vaddr; 530 break; 531 default: 532 UPRINTF ("ELF %d section ??\n", phdr[i].p_type); 533 } 534 } 535 536 vmspace->vm_tsize = text_size >> PAGE_SHIFT; 537 vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr; 538 vmspace->vm_dsize = data_size >> PAGE_SHIFT; 539 vmspace->vm_daddr = (caddr_t)(uintptr_t)data_addr; 540 541 addr = 2L*MAXDSIZ; /* May depend on OS type XXX */ 542 543 imgp->entry_addr = entry; 544 545 /* 546 * So which kind (brand) of ELF binary do we have at hand 547 * FreeBSD, Linux, SVR4 or something else ?? 548 * If its has a interpreter section try that first 549 */ 550 if (interp) { 551 for (i=0; i<MAX_BRANDS; i++) { 552 if (elf_brand_list[i] != NULL) { 553 if (!strcmp(interp, elf_brand_list[i]->interp_path)) { 554 imgp->proc->p_sysent = 555 elf_brand_list[i]->sysvec; 556 strcpy(path, elf_brand_list[i]->emul_path); 557 strcat(path, elf_brand_list[i]->interp_path); 558 UPRINTF("interpreter=<%s> %s\n", 559 elf_brand_list[i]->interp_path, 560 elf_brand_list[i]->emul_path); 561 break; 562 } 563 } 564 } 565 } 566 567 /* 568 * If there is no interpreter, or recognition of it 569 * failed, se if the binary is branded. 570 */ 571 if (!interp || i == MAX_BRANDS) { 572 brand = (char *)&(hdr->e_ident[EI_BRAND]); 573 for (i=0; i<MAX_BRANDS; i++) { 574 if (elf_brand_list[i] != NULL) { 575 if (!strcmp(brand, elf_brand_list[i]->brand)) { 576 imgp->proc->p_sysent = elf_brand_list[i]->sysvec; 577 if (interp) { 578 strcpy(path, elf_brand_list[i]->emul_path); 579 strcat(path, elf_brand_list[i]->interp_path); 580 UPRINTF("interpreter=<%s> %s\n", 581 elf_brand_list[i]->interp_path, 582 elf_brand_list[i]->emul_path); 583 } 584 break; 585 } 586 } 587 } 588 } 589 if (i == MAX_BRANDS) { 590 #ifndef __alpha__ 591 uprintf("ELF binary type not known\n"); 592 error = ENOEXEC; 593 goto fail; 594 #else 595 i = 0; /* assume freebsd */ 596 imgp->proc->p_sysent = elf_brand_list[i]->sysvec; 597 if (interp) { 598 strcpy(path, elf_brand_list[i]->emul_path); 599 strcat(path, elf_brand_list[i]->interp_path); 600 UPRINTF("interpreter=<%s> %s\n", 601 elf_brand_list[i]->interp_path, 602 elf_brand_list[i]->emul_path); 603 } 604 #endif 605 } 606 if (interp) { 607 if (error = elf_load_file(imgp->proc, 608 path, 609 &addr, /* XXX */ 610 &imgp->entry_addr)) { 611 uprintf("ELF interpreter %s not found\n", path); 612 goto fail; 613 } 614 } 615 616 UPRINTF("Executing %s binary\n", elf_brand_list[i]->brand); 617 618 /* 619 * Construct auxargs table (used by the fixup routine) 620 */ 621 elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK); 622 elf_auxargs->execfd = -1; 623 elf_auxargs->phdr = proghdr; 624 elf_auxargs->phent = hdr->e_phentsize; 625 elf_auxargs->phnum = hdr->e_phnum; 626 elf_auxargs->pagesz = PAGE_SIZE; 627 elf_auxargs->base = addr; 628 elf_auxargs->flags = 0; 629 elf_auxargs->entry = entry; 630 elf_auxargs->trace = elf_trace; 631 632 imgp->auxargs = elf_auxargs; 633 imgp->interpreted = 0; 634 635 /* don't allow modifying the file while we run it */ 636 imgp->vp->v_flag |= VTEXT; 637 638 fail: 639 return error; 640 } 641 642 int 643 elf_coredump (p) 644 register struct proc *p; 645 { 646 /* Not implemented yet. */ 647 return EFAULT; 648 } 649 650 static int 651 elf_freebsd_fixup(long **stack_base, struct image_params *imgp) 652 { 653 Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs; 654 long *pos; 655 656 pos = *stack_base + (imgp->argc + imgp->envc + 2); 657 658 if (args->trace) { 659 AUXARGS_ENTRY(pos, AT_DEBUG, 1); 660 } 661 if (args->execfd != -1) { 662 AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 663 } 664 AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 665 AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 666 AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 667 AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 668 AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 669 AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 670 AUXARGS_ENTRY(pos, AT_BASE, args->base); 671 AUXARGS_ENTRY(pos, AT_NULL, 0); 672 673 free(imgp->auxargs, M_TEMP); 674 imgp->auxargs = NULL; 675 676 (*stack_base)--; 677 **stack_base = (long)imgp->argc; 678 return 0; 679 } 680 681 /* 682 * Tell kern_execve.c about it, with a little help from the linker. 683 * Since `const' objects end up in the text segment, TEXT_SET is the 684 * correct directive to use. 685 */ 686 static const struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; 687 TEXT_SET(execsw_set, elf_execsw); 688 689