Assembly x86_64汇编命令行参数

Assembly x86_64汇编命令行参数,assembly,stack,command-line-arguments,x86-64,Assembly,Stack,Command Line Arguments,X86 64,要在Mac OS X上获取x86_64中的命令行参数,我可以执行以下操作: _main: sub rsp, 8 ; 16 bit stack alignment mov rax, 0 mov rdi, format mov rsi, [rsp + 32] call _printf 其中格式为“%s”。rsi设置为argv[0] 因此,我从中得出了(我认为)堆栈最初的样子: top of stack <-

要在Mac OS X上获取x86_64中的命令行参数,我可以执行以下操作:

_main:
  sub   rsp, 8         ; 16 bit stack alignment
  mov   rax, 0
  mov   rdi, format
  mov   rsi, [rsp + 32]
  call  _printf
其中格式为“%s”。rsi设置为argv[0]

因此,我从中得出了(我认为)堆栈最初的样子:

 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
栈顶
你离得很近

argv
是数组指针,而不是数组所在的位置。在
C
中,它被写入
char**argv
,因此您必须执行两个级别的解引用才能获得字符串

 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
栈顶
根据(3.2.3,参数传递),将
main(int argc,char**argv)
的参数传递给(按从左到右的顺序)
rdi
rsi
,因为它们属于整数类
envp
,如果使用它,将被传递到
rdx
,以此类推。
gcc
将它们放入当前帧,如下所示(可能是为了方便?释放寄存器?):

当省略帧指针时,寻址相对于
rsp
。通常,
argv
将比
rbp
低八个字节(
argc
排在第一位,尽管这不是强制性的),因此:

# 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>
开场白之后 mov-rax,QWORD-PTR[rbp-0x10]#或者你可以从rsi等公司获得它。 添加rax,0x8 移动rsi,QWORD PTR[rax] mov edi,0x40064c#格式 拨打400418
啊,是的,这更有意义。但是,为什么当我这样做:“mov r10,[rsp+32]”然后“添加r10,8”,然后将r10传递给printf时,我会得到一个segfault?那应该是argv[1],对吗?等等,我的错。我认为argv实际上是“rsp+40”,而不是32。大概我现在很困惑,但是谢谢你的帮助
argc
argv
不在堆栈上,x86-64系统V传递寄存器中第一个最多6个整数/指针arg。如果调用
main
的东西在进程进入后没有对堆栈进行太多的调整(其中
argv[]
数组本身在堆栈上,因此
\u start
将执行类似于
mov edi,[rsp]
(argc)和
lea rsi,[rsp+8]
(argv)的操作,那么OP加载正好起作用获取
main
的参数(以及另一个带有RDI*8的LEA以获取envp)。可能是为了方便?不,因为您在禁用优化的情况下编译,所以它会将所有内容溢出到内存中,调试器可以在其中读写它们。如果您在正常优化的情况下编译,gcc将像手动一样使用寄存器值。
# 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>