【问题标题】:Where does the OS store argv and argc when a child process is executed?执行子进程时,操作系统将 argv 和 argc 存储在哪里?
【发布时间】:2014-12-12 13:04:26
【问题描述】:

我很难理解操作系统如何将数据从父进程的地址空间传递到子进程的地址空间。也就是说,在 C 程序中,argc 和 argv 在传递给 main 时存储在哪里?

我理解 argv 本质上是一个双指针。我不明白的是操作系统在将这些值加载到内核后对它们做了什么。在为子进程创建地址空间后,它是否会将这些值推送到新空间的堆栈中?我们显然不想传递指向另一个地址空间的指针。

为了记录,我正在使用 MIPS32 架构。

【问题讨论】:

    标签: c architecture operating-system main virtual-address-space


    【解决方案1】:

    在 Linux 上,至少在我使用过的架构上,该过程从 %esp 开始,指向如下内容:

    argc | argv[0] | argv[1] | ... argv[argc - 1] | argv[argc] == NULL | envp[0] | envp[1] ... envp[?] == NULL
    

    第一个调用的函数通常命名为_start,它的工作是计算(argc = %esp, argv = ((char *)%esp) + 1, envp = ((char *)%esp) + argc + 2),然后使用适当的调用约定调用main

    在 x86 上,参数通过堆栈传递。

    在 amd64 上,它们在寄存器 %rdi%rsi%rdx 中传递。

    在 mips 上,Google 告诉我使用了几种不同的调用约定 - 包括 O32、N32、N64 - 但它们都首先使用 $a0$a1$a2

    【讨论】:

    • 你能添加证据或相关来源的链接吗?
    • 现在指向参数的指针(即指向 argv 的指针)怎么样?如果参数本身被扔到堆栈上,指针是否也被放置在堆栈上还是在参数寄存器中传递(我使用的是 MIPS 架构)?
    • @audiFanatic by "arguments" 我的意思是每个调用约定的函数参数:argcargvenvp;函数参数始终是值;之前的计算是指针值的计算方式(尽管第一个使用pop %esp 并摆脱一堆+4或+8是很常见的)。
    【解决方案2】:

    对于不同的操作系统,进程是不同的,并且确实会根据新进程的创建方式而有所不同。由于我更熟悉现代 Microsoft 操作系统的处理方式,因此我将从那里开始,并在最后引用 nix 的。

    当 [Microsoft] 操作系统创建进程时,它会分配一个进程环境块来保存特定于该进程的数据。其中包括调用程序的命令行参数。这个进程环境块是在目标进程的地址空间之外分配的,并且指向它的指针被提供给进程的入口点。子进程的进程环境块通常通过复制父进程的环境块到新进程的地址空间来初始化 - 不涉及直接共享内存。

    在基于 C 的程序的情况下,入口点不是程序员提供的main() 函数。相反,它是 C 运行时库提供的一个例程,负责在将控制权交给程序员的main() 之前初始化运行时环境。

    有很多东西要初始化,但其中一个方面是设置 argcargv 值。为此,运行时将查询进程环境块以查找调用它的程序名称和参数。然后(通常)从进程堆中为 argv 分配值(即,使用类似 malloc() 的东西),并将 argc 分配给找到的参数数量(加一,作为程序名称)。

    argc 和 argv 的实际值被压入堆栈,就像在 C 中传递的任何其他参数一样,因为 C 运行时对 main() 的调用只是一个普通的函数调用。

    因此,当您在子进程中的main() 中编写的代码访问 argv 时,它将从自己的进程堆中读取值。这些值的来源是进程环境块(由操作系统存储在本地地址空间中),最初是通过从父进程复制进程环境块来初始化的。

    在 *nix 平台上,情况有些不同。当前讨论的主要区别在于,nix 会将新进程的命令行参数直接存储到进程初始线程的堆栈空间中。 (它还在这里存储环境变量。)所以在 *nix 上,main 被调用,argv 参数指向存储在堆栈本身中的值。

    您可以在 execve 的联机帮助页中收集其中的一些内容,而 Michael Kerrisk 的 Linux Programming Interface 在第 6.4 节中有很好的描述,您可能会在网上找到摘录。

    【讨论】:

    猜你喜欢
    • 2011-12-05
    • 1970-01-01
    • 2020-07-08
    • 2012-06-09
    • 2010-11-17
    • 2013-08-28
    • 2017-11-10
    • 2013-11-26
    • 1970-01-01
    相关资源
    最近更新 更多