Brandon oubiub
Brandon oubiub

Reputation: 311

x86_64 Assembly Command Line Arguments

To get the command line arguments in x86_64 on Mac OS X, I can do the following:

_main:
  sub   rsp, 8         ; 16 bit stack alignment
  mov   rax, 0
  mov   rdi, format
  mov   rsi, [rsp + 32]
  call  _printf

Where format is "%s". rsi gets set to argv[0].

So, from this, I drew out what (I think) the stack looks like initially:

 top of stack
               <- rsp after alignment
return address <- rsp at beginning (aligned rsp + 8)
  [something]  <- rsp + 16
    argc       <- rsp + 24
   argv[0]     <- rsp + 32
   argv[1]     <- rsp + 40
    ...            ...
bottom of stack

And so on. Sorry if that's hard to read. I'm wondering what [something] is. After a few tests, I find that it is usually just 0. However, occasionally, it is some (seemingly) random number.

Also, could you tell me if the rest of my stack drawing is correct?

Upvotes: 3

Views: 24869

Answers (2)

Michael F
Michael F

Reputation: 40830

According to the AMD64 ABI (3.2.3, Parameter Passing), the parameters for main(int argc, char **argv) are passed to (in left-to-right order) rdi & rsi because they are of INTEGER class. envp, if it were used, would be passed into rdx, and so forth. gcc places them into the current frame as follows (presumably for convenience? freeing up registers?):

mov    DWORD PTR [rbp-0x4],  edi
mov    QWORD PTR [rbp-0x10], rsi

When the frame pointer is omitted, the addressing is relative to rsp. Normally, argv would be one eightbyte below rbp (argc comes first, although that's not mandated) and therefore:

# after prologue
mov    rax, QWORD PTR [rbp-0x10] # or you could grab it from rsi, etc.
add    rax, 0x8
mov    rsi, QWORD PTR [rax]
mov    edi, 0x40064c # format
call   400418 <printf@plt>

Upvotes: 2

wallyk
wallyk

Reputation: 57774

You have it close.

argv is an array pointer, not where the array is. In C it is written char **argv, so you have to do two levels of dereferencing to get to the strings.

 top of stack
               <- rsp after alignment
return address <- rsp at beginning (aligned rsp + 8)
  [something]  <- rsp + 16
    argc       <- rsp + 24
   argv        <- rsp + 32
   envp        <- rsp + 40  (in most Unix-compatible systems, the environment
    ...            ...       string array, char **envp)
bottom of stack
 ...
somewhere else:
   argv[0]     <- argv+0:   address of first parameter (program path or name)
   argv[1]     <- argv+8:   address of second parameter (first command line argument)
   argv[2]     <- argv+16:  address of third parameter (second command line argument)
    ...
   argv[argc]  <-  argv+argc*8:  NULL

Upvotes: 1

Related Questions