假设我有一个c程序名称hello.out。它会永远每5秒打印一个hello world。当我执行该程序时。该程序的实例称为进程。现在,当我在终端 - 前台执行它时。流程页面表会发生什么?谁填写了流程表,并在其中添加了一个条目。怎么回事?我理解有维护它的struct任务。谁填写了这个任务结构,它是加载器吗?
strace ./hello.out
execve("./hello.out", ["./hello.out"], [/* 54 vars */]) = 0
brk(0) = 0x9e3e000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7713000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=176783, ...}) = 0
mmap2(NULL, 176783, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb76e7000
close(3) = 0
open("/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\20\250\366K4\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=2012656, ...}) = 0
mmap2(0x4bf51000, 1772124, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x4bf51000
mprotect(0x4c0fb000, 4096, PROT_NONE) = 0
mmap2(0x4c0fc000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1aa) = 0x4c0fc000
mmap2(0x4c0ff000, 10844, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4c0ff000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76e6000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb76e66c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0x4c0fc000, 8192, PROT_READ) = 0
mprotect(0x4bf49000, 4096, PROT_READ) = 0
munmap(0xb76e7000, 176783) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 7), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7712000
write(1, "Hello world\r\n", 13Hello world
) = 13
exit_group(0) = ?
+++ exited with 0 +++
叉子在哪里,这里发生了什么。我可以看到这些是系统调用。我可以看出printf用stdout(最后一行)进行写调用。但叉子在哪里?这个brk是什么?为什么先行? mmap2在这做什么?还有,fstat?我试图解码这个,我无法详细了解它?请帮帮我。
答案 0 :(得分:0)
当您在终端上调用程序时,实际上您要求shell运行您的程序。例如,运行程序后,
./hello.out
现在shell将读取此命令并使用fork()函数创建进程。然后fork()调用系统调用sys_clone(从版本2.3.3开始,传递参数,因为它的行为类似于fork()系统调用)。 sys_clone()调用do_fork()。 do_fork()使用所有资源创建进程(大多数资源从父进程复制),并将进程的所有信息存储在struct task_struct类型的对象中。
fork()返回后,shell程序现在调用另一个系统调用execve(),用子进程上下文中的程序hello.out替换新创建的进程的地址空间。 execve()系统调用使用帮助ELF代码读取hello.out的内容并填充内存并调用程序的入口点。在此过程中,程序hello.out的名称也会写入流程结构中。您可以调用谁将此程序加载为加载程序(内核的一部分)。如果程序hello.out使用任何共享库,则在动态链接器的帮助下完成。