1
votes

I'm currently implementing the execv syscall into my own kernel. However, I managed to calculate the argument count(argc) in user space and passed argc and argv to my kernel exec function via a system call.

Actually, I don't know how to pass these two variables now to the new user threads main function. I allocated a new stack page and stored argc and argv in sequence onto this page space. My I idea was to point either EDI or ESI user register to the first argument (argc) followed by the argv array.

I'm not sure if it is correct to use EDI or ESI for this purpose. Does anybody know how the arguments get passed inside other kernels?

1

1 Answers

1
votes

You need to setup the user stack properly and then the entry point of the ELF executable would be responsible for locating argc and argv on the stack. The function in the Linux kernel responsible for seting up the stack is create_elf_tables. For a visual representation, you can check out this nice figure from this great LWN.net article:

------------------------------------------------------------- 0x7fff6c845000
 0x7fff6c844ff8: 0x0000000000000000
        _  4fec: './stackdump\0'                      <------+
  env  /   4fe2: 'ENVVAR2=2\0'                               |    <----+
       \_  4fd8: 'ENVVAR1=1\0'                               |   <---+ |
       /   4fd4: 'two\0'                                     |       | |     <----+
 args |    4fd0: 'one\0'                                     |       | |    <---+ |
       \_  4fcb: 'zero\0'                                    |       | |   <--+ | |
           3020: random gap padded to 16B boundary           |       | |      | | |
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|       | |      | | |
           3019: 'x86_64\0'                        <-+       |       | |      | | |
 auxv      3009: random data: ed99b6...2adcc7        | <-+   |       | |      | | |
 data      3000: zero padding to align stack         |   |   |       | |      | | |
. . . . . . . . . . . . . . . . . . . . . . . . . . .|. .|. .|       | |      | | |
           2ff0: AT_NULL(0)=0                        |   |   |       | |      | | |
           2fe0: AT_PLATFORM(15)=0x7fff6c843019    --+   |   |       | |      | | |
           2fd0: AT_EXECFN(31)=0x7fff6c844fec      ------|---+       | |      | | |
           2fc0: AT_RANDOM(25)=0x7fff6c843009      ------+           | |      | | |
  ELF      2fb0: AT_SECURE(23)=0                                     | |      | | |
auxiliary  2fa0: AT_EGID(14)=1000                                    | |      | | |
 vector:   2f90: AT_GID(13)=1000                                     | |      | | |
(id,val)   2f80: AT_EUID(12)=1000                                    | |      | | |
  pairs    2f70: AT_UID(11)=1000                                     | |      | | |
           2f60: AT_ENTRY(9)=0x4010c0                                | |      | | |
           2f50: AT_FLAGS(8)=0                                       | |      | | |
           2f40: AT_BASE(7)=0x7ff6c1122000                           | |      | | |
           2f30: AT_PHNUM(5)=9                                       | |      | | |
           2f20: AT_PHENT(4)=56                                      | |      | | |
           2f10: AT_PHDR(3)=0x400040                                 | |      | | |
           2f00: AT_CLKTCK(17)=100                                   | |      | | |
           2ef0: AT_PAGESZ(6)=4096                                   | |      | | |
           2ee0: AT_HWCAP(16)=0xbfebfbff                             | |      | | |
           2ed0: AT_SYSINFO_EHDR(33)=0x7fff6c86b000                  | |      | | |
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .        | |      | | |
           2ec8: environ[2]=(nil)                                    | |      | | |
           2ec0: environ[1]=0x7fff6c844fe2         ------------------|-+      | | |
           2eb8: environ[0]=0x7fff6c844fd8         ------------------+        | | |
           2eb0: argv[3]=(nil)                                                | | |
           2ea8: argv[2]=0x7fff6c844fd4            ---------------------------|-|-+
           2ea0: argv[1]=0x7fff6c844fd0            ---------------------------|-+
           2e98: argv[0]=0x7fff6c844fcb            ---------------------------+
 0x7fff6c842e90: argc=3

At the first instruction of the entry point of the ELF binary (glibc calls it _start), the top of the stack (0(%rsp)) would point to argc, as shown in the figure. Then follows the argv array, which is just an array of pointers. The environment variables array is also part of the ABI, as well as the ELF auxiliary vector (which may be used by the glibc initialization code). Although if you know for sure (or assume) that the ELF binary is not going to use the environment variables array or the auxiliary vector, then you just setup argv and argc as shown in the figure.