程序员的自我修养 ch6 可执行文件的装载与进程
来源:互联网 发布:师洋的淘宝骂人截图 编辑:程序博客网 时间:2024/06/08 20:02
参考《程序员的自我修养》ch6
1. MMU
MMU是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件机制的内存访问授权。在ELF中把这些属性相似的,又连在一起的段叫做一个“segment”,而系统正是按照“segment”而不是“section”来映射可执行文件的。
>> cat sleep.c#include <stdlib.h>int main(){ while(1) { sleep(1000); }}>> gcc -m32 sleep.c>> gcc -m32 -static sleep.c -o static.elf>> file a.outa.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked (uses shared libs), not stripped>> file static.elfstatic.elf: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.8, statically linked, not stripped>> ldd static.elf not a dynamic executable>> ldd a.out linux-gate.so.1 => (0xffffe000) libc.so.6 => /lib32/libc.so.6 (0xf7dac000) /lib/ld-linux.so.2 (0xf7f0e000)
>> readelf -S static.elfThere are 33 section headers, starting at offset 0x80014:Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .note.ABI-tag NOTE 080480d4 0000d4 000020 00 A 0 0 4 [ 2] .init PROGBITS 080480f4 0000f4 000030 00 AX 0 0 4 [ 3] .text PROGBITS 08048130 000130 05f448 00 AX 0 0 16 [ 4] __libc_freeres_fn PROGBITS 080a7580 05f580 001022 00 AX 0 0 16 [ 5] .fini PROGBITS 080a85a4 0605a4 00001c 00 AX 0 0 4 [ 6] .rodata PROGBITS 080a85c0 0605c0 017150 00 A 0 0 32 [ 7] __libc_subfreeres PROGBITS 080bf710 077710 00002c 00 A 0 0 4 [ 8] __libc_atexit PROGBITS 080bf73c 07773c 000004 00 A 0 0 4 [ 9] .eh_frame PROGBITS 080bf740 077740 004bc8 00 A 0 0 4 [10] .gcc_except_table PROGBITS 080c4308 07c308 0000fd 00 A 0 0 1 [11] .tdata PROGBITS 080c5408 07c408 000010 00 WAT 0 0 4 [12] .tbss NOBITS 080c5418 07c418 000018 00 WAT 0 0 4 [13] .ctors PROGBITS 080c5418 07c418 000008 00 WA 0 0 4 [14] .dtors PROGBITS 080c5420 07c420 00000c 00 WA 0 0 4 [15] .jcr PROGBITS 080c542c 07c42c 000004 00 WA 0 0 4 [16] .data.rel.ro PROGBITS 080c5430 07c430 000034 00 WA 0 0 4 [17] .got PROGBITS 080c5464 07c464 000008 04 WA 0 0 4 [18] .got.plt PROGBITS 080c546c 07c46c 00000c 04 WA 0 0 4 [19] .data PROGBITS 080c5480 07c480 000714 00 WA 0 0 32 [20] .bss NOBITS 080c5ba0 07cb94 0019d8 00 WA 0 0 32 [21] __libc_freeres_pt NOBITS 080c7578 07cb94 000014 00 WA 0 0 4 [22] .comment PROGBITS 00000000 07cb94 002e6e 00 0 0 1 [23] .debug_aranges PROGBITS 00000000 07fa08 000050 00 0 0 8 [24] .debug_pubnames PROGBITS 00000000 07fa58 000025 00 0 0 1 [25] .debug_info PROGBITS 00000000 07fa7d 0001a9 00 0 0 1 [26] .debug_abbrev PROGBITS 00000000 07fc26 00006f 00 0 0 1 [27] .debug_line PROGBITS 00000000 07fc95 00012b 00 0 0 1 [28] .debug_str PROGBITS 00000000 07fdc0 0000bb 01 MS 0 0 1 [29] .debug_ranges PROGBITS 00000000 07fe80 000040 00 0 0 8 [30] .shstrtab STRTAB 00000000 07fec0 000152 00 0 0 1 [31] .symtab SYMTAB 00000000 08053c 007550 10 32 799 4 [32] .strtab STRTAB 00000000 087a8c 006c1c 00 0 0 1Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)
>> readelf -l static.elfElf file type is EXEC (Executable file)Entry point 0x8048130There are 5 program headers, starting at offset 52Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x08048000 0x08048000 0x7c405 0x7c405 R E 0x1000 LOAD 0x07c408 0x080c5408 0x080c5408 0x0078c 0x02184 RW 0x1000 NOTE 0x0000d4 0x080480d4 0x080480d4 0x00020 0x00020 R 0x4 TLS 0x07c408 0x080c5408 0x080c5408 0x00010 0x00028 R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 Section to Segment mapping: Segment Sections... 00 .note.ABI-tag .init .text __libc_freeres_fn .fini .rodata __libc_subfreeres __libc_atexit .eh_frame .gcc_except_table 01 .tdata .ctors .dtors .jcr .data.rel.ro .got .got.plt .data .bss __libc_freeres_ptrs 02 .note.ABI-tag 03 .tdata .tbss 04
数据结构定义,
/* Program segment header. */typedef struct{ Elf32_Word p_type; /* Segment type */ Elf32_Off p_offset; /* Segment file offset */ Elf32_Addr p_vaddr; /* Segment virtual address */ Elf32_Addr p_paddr; /* Segment physical address */ Elf32_Word p_filesz; /* Segment size in file */ Elf32_Word p_memsz; /* Segment size in memory */ Elf32_Word p_flags; /* Segment flags */ Elf32_Word p_align; /* Segment alignment */} Elf32_Phdr;
2. 堆和栈
VMA除了以上功能外,还被操作系统用来对进程的地址空间进行管理。 进程执行时的栈(Stack)和堆(Heap)在虚拟地址空间中也是以VMA的形式存在的。 可以通过查看“cat /proc/进程号/maps”来查看进程额虚拟地址空间分布。
>> ./static.elf &[1] 23099>> cat /proc/23099/maps08048000-080c5000 r-xp 00000000 08:06 21898678 /local/honghaos/c/ch6/static.elf080c5000-080c6000 rw-p 0007c000 08:06 21898678 /local/honghaos/c/ch6/static.elf080c6000-080ea000 rw-p 080c6000 00:00 0 [heap]fff38000-fff4d000 rw-p 7ffffffea000 00:00 0 [stack]ffffe000-fffff000 r-xp ffffe000 00:00 0 [vdso]
通过上述命令,我们可以看到有两个匿名虚拟内存区域(Anonymous Virtual Memory Area),它们分别是[heap]和[stack]。 另外有一个特殊的的VMA叫做“vdso”,它的地址已经位于内核空间了(大于0xC0000000),实际上它是一个内核模块, 可以通过访问这个VMA来跟内核进行一些通信。
在此再小结下进程虚拟地址空间的概念:操作系统通过给进程空间划分一个个VMA来管理进程的虚拟空间。 基本原则是将相同权限属性的、有相同映像文件的映射成一个VMA。 一个进程基本上可以分为如下几种VMA区域:
a. 代码VMA,权限只读、可执行;有映像文件。
b. 数据VMA,权限可读写、可执行;有映像文件。
c. 堆VMA,权限可读写、可执行;无映像文件,匿名,可向上扩展。
d. 栈VMA,权限可读写、不可执行;无映像文件,匿名,可向下扩展。
进程刚开始启动时,需要一些进程运行的环境,最基本的就是系统环境变量和进程的运行参数。 很常见的一种做法就是操作系统在进程启动前将这些信息提前保存到进程的虚拟空间的栈中(也即是VMA中的Stack VMA)。 然后再在main函数中读取这些参数,如argc和argv。
3. Linux内核装载ELF过程简介
在bash下执行一个程序时,Linux是怎样装载这个ELF文件并执行的呢?
首先bash调用fork()系统调用创建一个新的进程,然后新的进程调用execve()系统调用执行指定的ELF文件。 bash进程继续返回等待新进程执行结束,然后重新等待用户输入命令。
>> cat minbash.c#include <stdio.h>#include <sys/types.h>#include <unistd.h>int main(){ char buf[1024] = {0}; pid_t pid; while(1) { printf("minibash$"); scanf("%s", buf); pid = fork(); if(pid == 0) { if(execlp(buf, 0) < 0) { printf("error!\n"); } } else if(pid > 0) { int status; waitpid(pid, &status, 0); } else { printf("fork error %d\n", pid); } } return 0;}>> ./a.outminibash$/bin/lsa.out malloc.c minbash.c sleep.c static.elfminibash$lsa.out malloc.c minbash.c sleep.c static.elfminibash$dateWed Jan 16 07:19:20 CST 2013minibash$exiterror!
系统内核代码,
arch/m32r/kernel/process.c, line 292
289/* 290 * sys_execve() executes a new program. 291 */ 292asmlinkage int sys_execve(const char __user *ufilename, 293 const char __user *const __user *uargv, 294 const char __user *const __user *uenvp, 295 unsigned long r3, unsigned long r4, unsigned long r5, 296 unsigned long r6, struct pt_regs regs) 297{ 298 int error; 299 struct filename *filename; 300 301 filename = getname(ufilename); 302 error = PTR_ERR(filename); 303 if (IS_ERR(filename)) 304 goto out; 305 306 error = do_execve(filename->name, uargv, uenvp, ®s); 307 putname(filename); 308out: 309 return error; 310}
linux/fs/exec.c
1263/* 1264 * Fill the binprm structure from the inode. 1265 * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes1266 *1267 * This may be called multiple times for binary chains (scripts for example).1268 */1269int prepare_binprm(struct linux_binprm *bprm)
脚本程序的开始部分 “#!”也是magic number
1364/*1365 * cycle the list of binary formats handler, until one recognizes the image1366 */1367int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
search_binary_handler()会通过判断文件头部的魔数确定文件的格式,并且调用相应的装载处理过程。例如,3.1 加载elf文件
fs/binfmt_elf.c, line 561
561static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) 562{ 563 struct file *interpreter = NULL; /* to shut gcc up */ 564 unsigned long load_addr = 0, load_bias = 0; 565 int load_addr_set = 0; 566 char * elf_interpreter = NULL; 567 unsigned long error; 568 struct elf_phdr *elf_ppnt, *elf_phdata; 569 unsigned long elf_bss, elf_brk; 570 int retval, i; 571 unsigned int size; 572 unsigned long elf_entry; 573 unsigned long interp_load_addr = 0; 574 unsigned long start_code, end_code, start_data, end_data; 575 unsigned long reloc_func_desc __maybe_unused = 0; 576 int executable_stack = EXSTACK_DEFAULT; 577 unsigned long def_flags = 0; 578 struct { 579 struct elfhdr elf_ex; 580 struct elfhdr interp_elf_ex; 581 } *loc; 582 583 loc = kmalloc(sizeof(*loc), GFP_KERNEL); 584 if (!loc) { 585 retval = -ENOMEM; 586 goto out_ret; 587 } 588 589 /* Get the exec-header */ 590 loc->elf_ex = *((struct elfhdr *)bprm->buf); 591 592 retval = -ENOEXEC; 593 /* First of all, some simple consistency checks */ 594 if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0) 595 goto out; 596 597 if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN) 598 goto out; 599 if (!elf_check_arch(&loc->elf_ex)) 600 goto out; 601 if (!bprm->file->f_op || !bprm->file->f_op->mmap) 602 goto out; 603 604 /* Now read in all of the header information */ 605 if (loc->elf_ex.e_phentsize != sizeof(struct elf_phdr)) 606 goto out; 607 if (loc->elf_ex.e_phnum < 1 || 608 loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr)) 609 goto out; 610 size = loc->elf_ex.e_phnum * sizeof(struct elf_phdr); 611 retval = -ENOMEM; 612 elf_phdata = kmalloc(size, GFP_KERNEL); 613 if (!elf_phdata) 614 goto out; 615 616 retval = kernel_read(bprm->file, loc->elf_ex.e_phoff, 617 (char *)elf_phdata, size); 618 if (retval != size) { 619 if (retval >= 0) 620 retval = -EIO; 621 goto out_free_ph; 622 } 623 624 elf_ppnt = elf_phdata; 625 elf_bss = 0; 626 elf_brk = 0; 627 628 start_code = ~0UL; 629 end_code = 0; 630 start_data = 0; 631 end_data = 0; 632 633 for (i = 0; i < loc->elf_ex.e_phnum; i++) { 634 if (elf_ppnt->p_type == PT_INTERP) { 635 /* This is the program interpreter used for 636 * shared libraries - for now assume that this 637 * is an a.out format binary 638 */ 639 retval = -ENOEXEC; 640 if (elf_ppnt->p_filesz > PATH_MAX || 641 elf_ppnt->p_filesz < 2) 642 goto out_free_ph; 643 644 retval = -ENOMEM; 645 elf_interpreter = kmalloc(elf_ppnt->p_filesz, 646 GFP_KERNEL); 647 if (!elf_interpreter) 648 goto out_free_ph; 649 650 retval = kernel_read(bprm->file, elf_ppnt->p_offset, 651 elf_interpreter, 652 elf_ppnt->p_filesz); 653 if (retval != elf_ppnt->p_filesz) { 654 if (retval >= 0) 655 retval = -EIO; 656 goto out_free_interp; 657 } 658 /* make sure path is NULL terminated */ 659 retval = -ENOEXEC; 660 if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') 661 goto out_free_interp; 662 663 interpreter = open_exec(elf_interpreter); 664 retval = PTR_ERR(interpreter); 665 if (IS_ERR(interpreter)) 666 goto out_free_interp; 667 668 /* 669 * If the binary is not readable then enforce 670 * mm->dumpable = 0 regardless of the interpreter's 671 * permissions. 672 */ 673 would_dump(bprm, interpreter); 674 675 retval = kernel_read(interpreter, 0, bprm->buf, 676 BINPRM_BUF_SIZE); 677 if (retval != BINPRM_BUF_SIZE) { 678 if (retval >= 0) 679 retval = -EIO; 680 goto out_free_dentry; 681 } 682 683 /* Get the exec headers */ 684 loc->interp_elf_ex = *((struct elfhdr *)bprm->buf); 685 break; 686 } 687 elf_ppnt++; 688 } 689 690 elf_ppnt = elf_phdata; 691 for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) 692 if (elf_ppnt->p_type == PT_GNU_STACK) { 693 if (elf_ppnt->p_flags & PF_X) 694 executable_stack = EXSTACK_ENABLE_X; 695 else 696 executable_stack = EXSTACK_DISABLE_X; 697 break; 698 } 699 700 /* Some simple consistency checks for the interpreter */ 701 if (elf_interpreter) { 702 retval = -ELIBBAD; 703 /* Not an ELF interpreter */ 704 if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) 705 goto out_free_dentry; 706 /* Verify the interpreter has a valid arch */ 707 if (!elf_check_arch(&loc->interp_elf_ex)) 708 goto out_free_dentry; 709 } 710 711 /* Flush all traces of the currently running executable */ 712 retval = flush_old_exec(bprm); 713 if (retval) 714 goto out_free_dentry; 715 716 /* OK, This is the point of no return */ 717 current->mm->def_flags = def_flags; 718 719 /* Do this immediately, since STACK_TOP as used in setup_arg_pages 720 may depend on the personality. */ 721 SET_PERSONALITY(loc->elf_ex); 722 if (elf_read_implies_exec(loc->elf_ex, executable_stack)) 723 current->personality |= READ_IMPLIES_EXEC; 724 725 if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) 726 current->flags |= PF_RANDOMIZE; 727 728 setup_new_exec(bprm); 729 730 /* Do this so that we can load the interpreter, if need be. We will 731 change some of these later */ 732 current->mm->free_area_cache = current->mm->mmap_base; 733 current->mm->cached_hole_size = 0; 734 retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), 735 executable_stack); 736 if (retval < 0) { 737 send_sig(SIGKILL, current, 0); 738 goto out_free_dentry; 739 } 740 741 current->mm->start_stack = bprm->p; 742 743 /* Now we do a little grungy work by mmapping the ELF image into 744 the correct location in memory. */ 745 for(i = 0, elf_ppnt = elf_phdata; 746 i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { 747 int elf_prot = 0, elf_flags; 748 unsigned long k, vaddr; 749 750 if (elf_ppnt->p_type != PT_LOAD) 751 continue; 752 753 if (unlikely (elf_brk > elf_bss)) { 754 unsigned long nbyte; 755 756 /* There was a PT_LOAD segment with p_memsz > p_filesz 757 before this one. Map anonymous pages, if needed, 758 and clear the area. */ 759 retval = set_brk(elf_bss + load_bias, 760 elf_brk + load_bias); 761 if (retval) { 762 send_sig(SIGKILL, current, 0); 763 goto out_free_dentry; 764 } 765 nbyte = ELF_PAGEOFFSET(elf_bss); 766 if (nbyte) { 767 nbyte = ELF_MIN_ALIGN - nbyte; 768 if (nbyte > elf_brk - elf_bss) 769 nbyte = elf_brk - elf_bss; 770 if (clear_user((void __user *)elf_bss + 771 load_bias, nbyte)) { 772 /* 773 * This bss-zeroing can fail if the ELF 774 * file specifies odd protections. So 775 * we don't check the return value 776 */ 777 } 778 } 779 } 780 781 if (elf_ppnt->p_flags & PF_R) 782 elf_prot |= PROT_READ; 783 if (elf_ppnt->p_flags & PF_W) 784 elf_prot |= PROT_WRITE; 785 if (elf_ppnt->p_flags & PF_X) 786 elf_prot |= PROT_EXEC; 787 788 elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; 789 790 vaddr = elf_ppnt->p_vaddr; 791 if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { 792 elf_flags |= MAP_FIXED; 793 } else if (loc->elf_ex.e_type == ET_DYN) { 794 /* Try and get dynamic programs out of the way of the 795 * default mmap base, as well as whatever program they 796 * might try to exec. This is because the brk will 797 * follow the loader, and is not movable. */ 798#ifdef CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE 799 /* Memory randomization might have been switched off 800 * in runtime via sysctl. 801 * If that is the case, retain the original non-zero 802 * load_bias value in order to establish proper 803 * non-randomized mappings. 804 */ 805 if (current->flags & PF_RANDOMIZE) 806 load_bias = 0; 807 else 808 load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); 809#else 810 load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); 811#endif 812 } 813 814 error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, 815 elf_prot, elf_flags, 0); 816 if (BAD_ADDR(error)) { 817 send_sig(SIGKILL, current, 0); 818 retval = IS_ERR((void *)error) ? 819 PTR_ERR((void*)error) : -EINVAL; 820 goto out_free_dentry; 821 } 822 823 if (!load_addr_set) { 824 load_addr_set = 1; 825 load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); 826 if (loc->elf_ex.e_type == ET_DYN) { 827 load_bias += error - 828 ELF_PAGESTART(load_bias + vaddr); 829 load_addr += load_bias; 830 reloc_func_desc = load_bias; 831 } 832 } 833 k = elf_ppnt->p_vaddr; 834 if (k < start_code) 835 start_code = k; 836 if (start_data < k) 837 start_data = k; 838 839 /* 840 * Check to see if the section's size will overflow the 841 * allowed task size. Note that p_filesz must always be 842 * <= p_memsz so it is only necessary to check p_memsz. 843 */ 844 if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz || 845 elf_ppnt->p_memsz > TASK_SIZE || 846 TASK_SIZE - elf_ppnt->p_memsz < k) { 847 /* set_brk can never work. Avoid overflows. */ 848 send_sig(SIGKILL, current, 0); 849 retval = -EINVAL; 850 goto out_free_dentry; 851 } 852 853 k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; 854 855 if (k > elf_bss) 856 elf_bss = k; 857 if ((elf_ppnt->p_flags & PF_X) && end_code < k) 858 end_code = k; 859 if (end_data < k) 860 end_data = k; 861 k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; 862 if (k > elf_brk) 863 elf_brk = k; 864 } 865 866 loc->elf_ex.e_entry += load_bias; 867 elf_bss += load_bias; 868 elf_brk += load_bias; 869 start_code += load_bias; 870 end_code += load_bias; 871 start_data += load_bias; 872 end_data += load_bias; 873 874 /* Calling set_brk effectively mmaps the pages that we need 875 * for the bss and break sections. We must do this before 876 * mapping in the interpreter, to make sure it doesn't wind 877 * up getting placed where the bss needs to go. 878 */ 879 retval = set_brk(elf_bss, elf_brk); 880 if (retval) { 881 send_sig(SIGKILL, current, 0); 882 goto out_free_dentry; 883 } 884 if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { 885 send_sig(SIGSEGV, current, 0); 886 retval = -EFAULT; /* Nobody gets to see this, but.. */ 887 goto out_free_dentry; 888 } 889 890 if (elf_interpreter) { 891 unsigned long interp_map_addr = 0; 892 893 elf_entry = load_elf_interp(&loc->interp_elf_ex, 894 interpreter, 895 &interp_map_addr, 896 load_bias); 897 if (!IS_ERR((void *)elf_entry)) { 898 /* 899 * load_elf_interp() returns relocation 900 * adjustment 901 */ 902 interp_load_addr = elf_entry; 903 elf_entry += loc->interp_elf_ex.e_entry; 904 } 905 if (BAD_ADDR(elf_entry)) { 906 force_sig(SIGSEGV, current); 907 retval = IS_ERR((void *)elf_entry) ? 908 (int)elf_entry : -EINVAL; 909 goto out_free_dentry; 910 } 911 reloc_func_desc = interp_load_addr; 912 913 allow_write_access(interpreter); 914 fput(interpreter); 915 kfree(elf_interpreter); 916 } else { 917 elf_entry = loc->elf_ex.e_entry; 918 if (BAD_ADDR(elf_entry)) { 919 force_sig(SIGSEGV, current); 920 retval = -EINVAL; 921 goto out_free_dentry; 922 } 923 } 924 925 kfree(elf_phdata); 926 927 set_binfmt(&elf_format); 928 929#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES 930 retval = arch_setup_additional_pages(bprm, !!elf_interpreter); 931 if (retval < 0) { 932 send_sig(SIGKILL, current, 0); 933 goto out; 934 } 935#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ 936 937 install_exec_creds(bprm); 938 retval = create_elf_tables(bprm, &loc->elf_ex, 939 load_addr, interp_load_addr); 940 if (retval < 0) { 941 send_sig(SIGKILL, current, 0); 942 goto out; 943 } 944 /* N.B. passed_fileno might not be initialized? */ 945 current->mm->end_code = end_code; 946 current->mm->start_code = start_code; 947 current->mm->start_data = start_data; 948 current->mm->end_data = end_data; 949 current->mm->start_stack = bprm->p; 950 951#ifdef arch_randomize_brk 952 if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) { 953 current->mm->brk = current->mm->start_brk = 954 arch_randomize_brk(current->mm); 955#ifdef CONFIG_COMPAT_BRK 956 current->brk_randomized = 1; 957#endif 958 } 959#endif 960 961 if (current->personality & MMAP_PAGE_ZERO) { 962 /* Why this, you ask??? Well SVr4 maps page 0 as read-only, 963 and some applications "depend" upon this behavior. 964 Since we do not have the power to recompile these, we 965 emulate the SVr4 behavior. Sigh. */ 966 error = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, 967 MAP_FIXED | MAP_PRIVATE, 0); 968 } 969 970#ifdef ELF_PLAT_INIT 971 /* 972 * The ABI may specify that certain registers be set up in special 973 * ways (on i386 %edx is the address of a DT_FINI function, for 974 * example. In addition, it may also specify (eg, PowerPC64 ELF) 975 * that the e_entry field is the address of the function descriptor 976 * for the startup routine, rather than the address of the startup 977 * routine itself. This macro performs whatever initialization to 978 * the regs structure is required as well as any relocations to the 979 * function descriptor entries when executing dynamically links apps. 980 */ 981 ELF_PLAT_INIT(regs, reloc_func_desc); 982#endif 983 984 start_thread(regs, elf_entry, bprm->p); 985 retval = 0; 986out: 987 kfree(loc); 988out_ret: 989 return retval; 990 991 /* error cleanup */ 992out_free_dentry: 993 allow_write_access(interpreter); 994 if (interpreter) 995 fput(interpreter); 996out_free_interp: 997 kfree(elf_interpreter); 998out_free_ph: 999 kfree(elf_phdata);1000 goto out;1001}
3.2 加载aout文件
fs/binfmt_aout.c, line 204
199/* 200 * These are the functions used to load a.out style executables and shared 201 * libraries. There is no binary dependent code anywhere else. 202 */ 203 204static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
3.3 加载script
fs/binfmt_script.c, line 17
17static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
最后,在load_elf_binary()中系统调用的返回地址已经被改成ELF程序的入口地址了“start_thread(regs, elf_entry, bprm->p);”。所以当sys_execve()系统调用从内核态返回到用户态时,EIP寄存器直接跳转到了ELF程序的出口地址,程序开始执行。
199void 200start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) 201{ 202 set_user_gs(regs, 0); 203 regs->fs = 0; 204 regs->ds = __USER_DS; 205 regs->es = __USER_DS; 206 regs->ss = __USER_DS; 207 regs->cs = __USER_CS; 208 regs->ip = new_ip; 209 regs->sp = new_sp; 210 regs->flags = X86_EFLAGS_IF; 211 /* 212 * force it to the iret return path by making it look as if there was 213 * some work pending. 214 */ 215 set_thread_flag(TIF_NOTIFY_RESUME); 216}
- 程序员的自我修养 ch6 可执行文件的装载与进程
- 程序员的自我修养--可执行文件的装载与进程
- 程序员的自我修养: 可执行文件的装载
- 可执行文件的装载与进程的一点小总结 《程序员的自我修养》·笔记
- 【程序员的自我修养】第6章 可执行文件的装载与进程
- 程序员的自我修养——6、可执行文件的装载与进程
- 程序员的自我修养——装载与进程
- 《程序员的自我修养》笔记--可执行文件的装载
- 《程序员的自我修养——链接、装载与库》
- 程序员的自我修养:链接、装载与库读后所感
- 《程序员的自我修养——链接、装载与库》
- 程序员的自我修养 -- 链接、装载与库
- 读书笔记之《程序员的自我修养--链接、装载与库》
- 《程序员的自我修养—链接、装载与库》
- 《程序员的自我修养》-链接、装载与库
- 程序员的自我修养--链接、装载与库
- 读《程序员的自我修养-链接装载与库》
- 《程序员的自我修养--链接、装载与库》
- 杭电2578
- BIT1048n以内约数最多的数
- 基于arm-linux-gcc的Apache和PHP移植
- 在不root手机的情况下读取Data目录下的文件
- Activity组件之一Service--- BindService & unBindService
- 程序员的自我修养 ch6 可执行文件的装载与进程
- 从Windows上用SSH链接接入Ubuntu
- HADOOP JAVA接口
- BitmapScale9Grid【九宫格类】
- 优化SQL Server数据库查询方法
- Knockoutjs介绍
- platform简单总结
- 稀疏编码
- 数据库索引的使用