linux系统调用execve

exec系列函数主要实现装入新的可执行文件或脚本镜像,并执行;调用后不再返回,而是跳转到新镜像的入口去执行。exec在linux上均是对execve系统调用的封装,除了下述内容外,进程其它内容均保持不变:1.将设置了处理函数的信号handler,重置为默认SIG_DFL2.内存映射,mmap3.SysV共享内存,shmat4.POSIX共享内存,shm_open5.POSI
摘要由CSDN通过智能技术生成

exec系列函数主要实现装入新的可执行文件或脚本镜像,并执行;调用后不再返回,而是跳转到新镜像的入口去执行。
exec在linux上均是对execve系统调用的封装,除了下述内容外,进程其它内容均保持不变:
1.将设置了处理函数的信号handler,重置为默认SIG_DFL
2.内存映射,mmap
3.SysV共享内存,shmat
4.POSIX共享内存,shm_open
5.POSIX消息队列,mq_overview
6.POSIX信号量,sem_overview
7.打开的目录,open_dir
8.内存锁,mlock/mlockall
9.exit处理,atexit/on_exit
10.浮点数环境,fenv


execve的主要作用为:
1.分配进程新的地址空间,将环境变量、main参数等拷贝到新地址空间的推栈中;
2.解析可执行文件,将代码、数据装入/映射到内存
3.进程新环境的设置,如关闭设置FD_CLOEXEC的文件等
4.设置execve函数返回到用户态时的执行地址;解析器入口地址或程序的入口地址

I.do_execve
execve系统调用是通过do_execve实现的,其处理流程如下:
1.进程分配并使用自己的文件描述符表,不再使用共享的文件描述符表
2.分配进程新的地址空间mm_struct,并复制老mm_struct的context,并分配一页大小的堆栈内存区。
3.打开可执行文件;检查可执行文件权限,并预读可执行文件的前BINPRM_BUF_SIZE=128字节数据到buf中
4.计算环境变量、main参数个数;并将这些参数复制到新地址空间的堆栈中
5.根据可执行文件的格式,查找对应的handler作后续处理;

do_execve的实现fs/exec.c:

1342 /*
1343  * sys_execve() executes a new program.
1344  */
1345 int do_execve(char * filename,
1346         char __user *__user *argv,
1347         char __user *__user *envp,
1348         struct pt_regs * regs)
1349 {

1355 
1356         retval = unshare_files(&displaced);
1357         if (retval)
1358                 goto out_ret;
1359 

1375         file = open_exec(filename);
1376         retval = PTR_ERR(file);
1377         if (IS_ERR(file))
1378                 goto out_unmark;
1379 

1385 
1386         retval = bprm_mm_init(bprm);
1387         if (retval)
1388                 goto out_file;
1389 
1390         bprm->argc = count(argv, MAX_ARG_STRINGS);
1391         if ((retval = bprm->argc) < 0)
1392                 goto out;
1393 
1394         bprm->envc = count(envp, MAX_ARG_STRINGS);
1395         if ((retval = bprm->envc) < 0)
1396                 goto out;
1397 
1398         retval = prepare_binprm(bprm);
1399         if (retval < 0)
1400                 goto out;
1401 
1402         retval = copy_strings_kernel(1, &bprm->filename, bprm);
1403         if (retval < 0)
1404                 goto out;
1405 
1406         bprm->exec = bprm->p;
1407         retval = copy_strings(bprm->envc, envp, bprm);
1408         if (retval < 0)
1409                 goto out;
1410 
1411         retval = copy_strings(bprm->argc, argv, bprm);
1412         if (retval < 0)
1413                 goto out;
1414 
1415         current->flags &= ~PF_KTHREAD;
1416         retval = search_binary_handler(bprm,regs);
1417         if (retval < 0)
1418                 goto out;
1419 

1453         return retval;
1454 }

字符串复制copy_strings函数:
1、将字符串从当前地址空间复制到新地址空间的堆栈中;
2、复制字符串时,使用的仍是老地址空间页表,所以不能使用新地址空间的堆栈地址直接复制,必须映射堆栈页帧到内核空间后再做复制操作。
3、由于字符串可能跨页,一个字符串可能存在两次页帧映射与复制

 

II.ELF格式文件处理
ELF格式文件处理主要对ELF文件进行解析,将可执行程序的代码及数据装载到内存中;并根据ELF文件信息,设置进程的环境

ELF格式:

ELF的管理信息主要由三部分组成:ELF头、程序头(程序段)表、节区表;一个段的地址空间通常包括一个或多个节区。
如数据段包括数据节区、BSS节区等

linux对ELF格式文件处理代码为load_elf_binary,主要流程如下:
i.根据ELF文件头数据,检查ELF文件的合法性
ii.根据ELF文件头中程序头表偏移和程序头数目,读出程序头表数据。
iii.根据解析器程序头信息,读出解析器可执行文件头数据放入buf中,以便后续处理
iv.清除原exec环境
  1.线程处理
    a.发送SIGKILL到线程组其它线程,杀死除自己以外所有的线程
    b.如果自己不是主线程,继承主线程信息并将自己设置成主线程
    c.删除信号时钟,并清空时钟信号
    d.如果信号处理handler表与其它进程共享,则创建并复制自己的handler表
  2.将可执行文件句柄设置成新的文件句柄
  3.切换地址空间,使用新的地址空间
v.设置新exec环境
  1.设置进程名称
  2.更新信号handler表,非忽略信号设置成行为,并清空mask
  3.关闭有FD_CLOEXEC标识的文件
vi. 堆栈内存区最后处理,更新内存区标识、权限,内存区可能重定位和扩容
vii.将ELF文件中PT_LOAD类型的程序段映射到内存中
  1.根据PT_LOAD类型的程序头信息,将可执行文件中代码段、数据段等通过文件映射方式映射到内存
  2.PT_LOAD一般包括代码段和数据段,数据段虚拟内存大小通常大于文件大小,多出的部分包括bss内存空间等;采用文件映射且程序段虚拟内存大小大于文件大小时,将多出部分清0(最后一个程序段中,多出部分通常采用匿名映射)
  3.设置start_code,end_code,start_data,end_data,elf_bss,elf_brk;一般情况,elf_bss=数据段虚拟地址+文件大小,elf_brk=数据段虚拟地址+虚拟内存大小
viii.对elf_bss与elf_brk之间的部分(BSS等)作匿名映射;
ix.设置exec返回用户空间后,执行代码的地址;如果有解析器(可执行程序通常是/lib/ld-linux.so.2,ld-linux.so.2作用是装载可执行文件所需的动态链接库),装载解析器,并将程序入口设置成解析器的入口;否则设置成镜像的入口点。
x.设置elf_table
  1.将main参数个数,参数字符串地址,NULL写到堆栈中
  2.将环境变量字符串地址,NULL写到堆栈中
  3.设置elf表,表项为(id,val)对;如程序的入口地址等 
xi.设置进程参数,如IP更改为新程序入口地址,堆栈切换;然后返回用户空间执行解析器代码或程序代码


ELF格式文件处理的实现fs/binfmt_elf.c:

563 static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 564 {
 565         struct file *interpreter = NULL; /* to shut gcc up */
 566         unsigned long load_addr = 0, load_bias = 0;
 567         int load_addr_set = 0;
 568         char * elf_interpreter = NULL;
 569         unsigned long error;
 570         struct elf_phdr *elf_ppnt, *elf_phdata;
 571         unsigned long elf_bss, elf_brk;
 572         int retval, i;
 573         unsigned int size;
 574         unsigned long elf_entry;
 575         unsigned long interp_load_addr = 0;
 576         unsigned long start_code, end_code, start_data, end_data;
 577         unsigned long reloc_func_desc 
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux系统调用号是指操作系统提供给用户程序调用的接口函数的编号。每个系统调用都有一个唯一的调用号,用于标识该函数。在Linux中,系统调用号是通过一个整数来表示的,不同的系统调用对应不同的整数值。用户程序可以通过系统调用号来调用相应的系统调用,从而实现对操作系统的各种功能的访问和控制。常见的Linux系统调用包括open、read、write、close、fork、execve等。 ### 回答2: Linux系统调用号是一个唯一的标识符,用于标识操作系统提供给用户程序调用的各种功能和服务。通过系统调用,用户程序可以请求操作系统执行特定的操作,如打开文件、创建进程、读取网络数据等。 在Linux中,每个系统调用都有一个特定的号码,这个号码是由操作系统内核分配的。这些号码是在系统的头文件中定义的,例如unistd.h文件中包含了系统调用号的定义。 系统调用号在调用系统调用时使用,用户程序可以使用相关的系统调用接口来执行操作系统提供的功能。用户程序通常会使用C语言的库函数封装系统调用,以提供更方便的接口给开发者使用。 系统调用号的分配通常是由操作系统的开发者决定的,他们会根据不同的功能和服务进行划分和分配。在Linux中,常见的系统调用号包括打开文件(open)、读取文件(read)、写入文件(write)、关闭文件(close)等。 系统调用号的使用可以在用户程序中通过系统调用指令实现,用户程序将需要执行的系统调用号存放在相应的寄存器中,并调用int 0x80或sysenter指令触发系统调用。 总之,Linux系统调用号是一种用于标识和调用操作系统功能的机制,它允许用户程序直接访问操作系统提供的各种服务和功能。这种机制使得用户程序可以与操作系统交互,实现更加强大和灵活的应用程序开发。 ### 回答3: Linux系统调用号是用于在用户空间程序和内核空间之间进行交互的接口标识符。当用户空间程序需要执行某些操作时,如创建进程、读写文件、网络通信等,就会调用相应的系统调用系统调用号是一个整数,每个系统调用都有一个唯一的号码与之对应。Linux内核通过系统调用号来识别用户空间程序请求的具体操作。系统调用号由内核定义并存储在一个表中,用户程序通过中断指令或软中断指令触发系统调用,将调用号传递给内核。 对于不同的操作,有不同的系统调用号。例如: 1. 创建进程的系统调用号是`fork`,对应的调用号是2; 2. 打开文件系统调用号是`open`,对应的调用号是5; 3. 写入文件系统调用号是`write`,对应的调用号是1; 4. 进程退出的系统调用号是`exit`,对应的调用号是60。 用户程序通过指定正确的系统调用号,将自己的请求传递给内核。内核收到请求后,根据调用号执行相应的操作,完成后再返回结果给用户程序。系统调用号的定义与使用遵循一定的规范,保证了用户程序与内核之间的正确通信和操作,是Linux系统中非常重要的一个概念。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值