`execve()` 如何调用特殊的启动例程和 main() 函数?

`execve()` 如何调用特殊的启动例程和 main() 函数?

当 C 程序由内核执行时execve()

  • 在哪里调用在调用 main 函数之前调用的execve()特殊启动例程?crt0

  • execve()main函数在哪里调用?

我找不到他们https://elixir.bootlin.com/linux/latest/source/fs/exec.c

从理解Linux内核开始,execve()内部寻找一个可以加载可执行文件linux_binfmt的对象并调用其方法来加载,同时还加载动态链接器来加载和链接可执行文件所使用的共享库。但书中没有说明如何从可执行文件中调用程序的启动例程和then 。load_binary()load_binary()execve()crt0main()

谢谢。

答案1

execve内核代码都不会调用该函数_start(可执行文件的入口点,无论它被称为什么)。

那是因为他们跑在不同的地方上下文;就好像它们在不同的机器上运行一样。

发生的情况是,内核execve在返回用户模式时安排系统调用,将IP(指令指针)寄存器设置为指向函数的开头_start,并将SP(堆栈指针)寄存器设置为指向函数的开头。 argv + env 字符串列表,所以从用户模式的角度来看效果就像某人将该函数调用_start为:

_start(argc, argv0, argv1, ... , NULL, env0, env1, ... NULL)

在所有参数都在堆栈上传递的调用约定中。

当然,在此之前,内核已经负责将这些 argv + env 复制到正确的位置,映射包含该_start函数的段等。


请注意,argv + env 字符串全部打包在一个块中,例如。

"prog\0arg1\0arg2\0VAR1=foo\0VAR2=bar\0"

该块开始和结束的虚拟地址可以通过文件访问/proc/PID/stat;引用手册procfs(5)页:

(48) arg_start  %lu  (since Linux 3.5)  [PT]
        Address  above  which  program  command-line arguments
        (argv) are placed.

(49) arg_end  %lu  (since Linux 3.5)  [PT]
        Address below program  command-line  arguments  (argv)
        are placed.

写入该地址将修改ps输出中出现的任何内容:

$ sleep 3600 3600 3600 3600 3600 3600 3600 &
[2] 4927
$ awk '{print $48,$49,$49-$48-1}' /proc/4927/stat
140735402952841 140735402952882 40
$ printf 'Somebody set up us the bomb Main screen turn on\0' | dd bs=1 count=40 of
=/proc/4927/mem seek=140735402952841 conv=notrunc
40+0 records in
40+0 records out
40 bytes copied, 0.000229779 s, 174 kB/s
$ ps 4927
  PID TTY      STAT   TIME COMMAND
 4927 pts/4    S      0:00 Somebody set up us the bomb Main screen

相关内容