【问题标题】:x86_64 Assembly Command Line Argumentsx86_64 汇编命令行参数
【发布时间】:2012-04-04 03:14:00
【问题描述】:

要在 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

等等。抱歉,如果这很难阅读。我想知道[东西]是什么。经过几次测试,我发现它通常只是 0。然而,偶尔,它是一些(看似)随机数。

另外,你能告诉我我的堆栈图的其余部分是否正确吗?

【问题讨论】:

    标签: assembly stack command-line-arguments x86-64


    【解决方案1】:

    根据AMD64 ABI(3.2.3,参数传递),main(int argc, char **argv) 的参数被传递给(从左到右的顺序)rdi & rsi,因为它们属于 INTEGER 类。 envp,如果被使用,将被传递到rdx,以此类推。 gcc 将它们按如下方式放置到当前帧中(大概是为了方便?释放寄存器?):

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

    当省略帧指针时,寻址是相对于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>
    

    【讨论】:

    • 大概是为了方便?不,因为你编译时禁用了优化,所以它会将所有内容溢出到调试器可以读取和写入它们的内存中。如果您使用常规优化进行编译,gcc 将像手动一样使用寄存器值。
    【解决方案2】:

    你已经接近了。

    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
    

    【讨论】:

    • 啊,是的,这更有意义。但是,为什么当我这样做时: "mov r10, [rsp + 32]" 然后 "add r10, 8" 然后将 r10 传递给 printf ,我得到一个段错误?那应该是 argv[1] 吧?
    • 等等,我的。我认为 argv 实际上是“rsp + 40”,而不是 32。也许吧。我现在很困惑,但感谢您的帮助!
    • argcargv 不在堆栈中,x86-64 System V 在寄存器中传递第一个最多 6 个整数/指针参数。如果调用 main 的东西在进程进入后没有对堆栈进行太多调整(argv[] 数组本身在堆栈上,所以_start 会做类似@ 987654331@ (argc) 和 lea rsi, [rsp+8] (argv) 以获取 main 的 args。(以及另一个具有 RDI*8 的 LEA 以获取 envp)。
    猜你喜欢
    • 2011-04-10
    • 2022-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-26
    • 1970-01-01
    • 2011-03-03
    • 2013-08-13
    相关资源
    最近更新 更多