当 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()
crt0
main()
谢谢。
答案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