Where is OS argv and argc stored when the child process is running?

I am having a hard time understanding how the OS transfers data from the address space of the parent process to the address space of the child process. Namely, in a C program, where argc and argv are stored when passed to main?

I understand how argv is essentially a double pointer. What I don't understand is what the OS does with these values โ€‹โ€‹after loading them into the kernel. By creating an address space for the child process, does it push those values โ€‹โ€‹onto the new space stack? We obviously don't want to pass pointers to another address space.

For the record, I am working with MIPS32 architecture.

+3


source to share


2 answers


On Linux, at least on the architecture I've been playing with, the process starts with %esp

pointing to something like:

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

      

The first function called is traditionally called _start

and its job is to evaluate (argc = %esp, argv = ((char *)%esp) + 1, envp = ((char *)%esp) + argc + 2)

, then call main

with the appropriate calling convention.



On x86, arguments are passed onto the stack.

In amd64, they are passed to registers %rdi

, %rsi

and %rdx

.

The mips Google informs me that there are several different conventional arrangements - including O32, N32, N64, but they all use the first $a0

, $a1

, $a2

.

+4


source


The process is different for different operating systems and really differs depending on how the new process is created. Since I'm more familiar with how modern Microsoft OS handles this, I'll start there and make a nix link at the end.

When [Microsoft] OS creates a process, it allocates a process box to store data specific to that process. This includes, but is not limited to, the command line arguments with which the program was invoked. This process environment block is allocated from the target process's address space and a pointer to it is provided to the process's entry point. The process environment block for a child process is usually initialized by copying the parent process environment block into the new process address space - no direct memory sharing.

In the case of a C-based program, the entry point is not a function main()

that the programmer provides. Rather, it is a procedure provided by the C runtime library that is responsible for initializing the runtime before passing control to the programmer main()

.

There are many things to do with initialization, but one aspect is setting the argc and argv values . To do this, the runtime will check the process environment block to find the name and parameters of the program with which it was called. It then (usually) allocates the values โ€‹โ€‹for argv from the process heap (i.e. using something like malloc()

) and assigns argc to the number of parameters found (plus one for the program name).



The actual values โ€‹โ€‹for argc and argv are pushed onto the stack like any other parameters passed to C, since a main()

C runtime call is a normal function call.

So, when the code you write internally main()

in the child process accesses argv, it will read values โ€‹โ€‹from the process's own heap. The source of these values โ€‹โ€‹is the process environment block (stored by the OS in the local address space) that was originally initialized by copying the process environment block from the parent process.

On * nix platforms, everything is completely different. The main difference for this discussion is that nix will store the command line arguments for the new process directly in the stack space of the initial process thread. (Environment variables are also stored here.) So, with * nix, main

called with the argv parameter pointing to the values โ€‹โ€‹stored on the stack itself.

You can compile some of these in the execve manpage , and Michael Kerrisk's Linux API has a good description in section 6.4 that you can find on the Internet.

+3


source







All Articles