assembly 汇编中的Linux 64命令行参数

vlju58qv  于 2023-08-06  发布在  Linux
关注(0)|答案(3)|浏览(110)

此说明适用于Linux 32位:当Linux程序开始时,所有指向命令行参数的指针都存储在堆栈上。参数的数量存储在0(%ebp),程序名存储在4(%ebp),参数从8(%ebp)开始存储。
我需要64位的相同信息。
编辑:我有一个工作代码示例,展示了如何使用argc,argv[0]和argv[1]:http://cubbi.com/fibonacci/asm.html

.globl _start
_start:
    popq    %rcx        # this is argc, must be 2 for one argument
    cmpq    $2,%rcx
    jne     usage_exit
    addq    $8,%rsp     # skip argv[0]
    popq    %rsi        # get argv[1]
    call ...
...
}

字符串
看起来参数在堆栈上。由于这个代码不清楚,我问这个问题。我的猜测是,我可以保持rsp在rbp,然后访问这些参数使用0(%rbp),8(%rbp),16(%rbp)等。是这样吗?

wnavrhmk

wnavrhmk1#

虽然大家所接受的答案已足够,但我仍想给予明确的答复,因为有些其他答案可能会令人混淆。
最重要(更多信息,请参见以下示例):在x86-64中,命令行参数通过堆栈传递:

(%rsp) -> number of arguments
8(%rsp) -> address of the name of the executable
16(%rsp) -> address of the first command line argument (if exists)
... so on ...

字符串
它与x86-64中传递的函数参数不同,后者使用%rdi%rsi等。
还有一件事:不应该从C main函数的反向工程中推导出该行为。C运行时提供入口点_start, Package 命令行参数,并将main作为公共函数调用。为了了解它,让我们考虑下面的例子。

没有带-nostdlib的C运行时/GCC

让我们看看这个简单的x86-64汇编程序,它只返回42:

.section .text
.globl _start
_start:   
    movq $60, %rax #60 -> exit
    movq $42, %rdi #return 42
    syscall #run kernel


我们构建它时采用了:

as --64 exit64.s -o exit64.o
ld -m elf_x86_64 exit64.o -o exit64


或与

gcc -nostdlib exit64.s -o exit64


在gdb中运行

./exit64 first second third


并在_start处的断点处停止。让我们检查一下寄存器:

(gdb) info registers
...
rsi            0x0  0
rdi            0x0  0
...


什么都没有。那一叠呢?

(gdb) x/5g $sp
0x7fffffffde40: 4   140737488347650
0x7fffffffde50: 140737488347711 140737488347717
0x7fffffffde60: 140737488347724


因此,堆栈上的第一个元素是4-预期的argc。接下来的4个值看起来很像指针。我们来看第二个指针:

(gdb) print (char[5])*(140737488347711)
$1 = "first"


正如所料,它是第一个命令行参数。
因此,有实验证据表明,在x86-64中,命令行参数是通过堆栈传递的。然而,只有通过阅读ABI(正如公认的答案所建议的那样),我们才能确定,情况确实如此。

使用C运行时

我们必须稍微修改一下程序,将_start重命名为main,因为入口点_start是由C运行时提供的。

.section .text
.globl main
main:   
    movq $60, %rax #60 -> exit
    movq $42, %rdi #return 42
    syscall #run kernel


我们使用以下代码构建它(默认情况下使用C运行时):

gcc exit64gcc.s -o exit64gcc


在gdb中运行

./exit64gcc first second third


并在main处的断点处停止。栈里有什么?

(gdb) x/5g $sp
0x7fffffffdd58: 0x00007ffff7a36f45  0x0000000000000000
0x7fffffffdd68: 0x00007fffffffde38  0x0000000400000000
0x7fffffffdd78: 0x00000000004004ed


它看起来不熟悉。还有收银机?

(gdb) info registers
...
rsi            0x7fffffffde38   140737488346680
rdi            0x4  4
...


我们可以看到,rdi包含argc的值。但是如果我们现在考察rsi中的指针,就会发生奇怪的事情:

(gdb) print (char[5])*($rsi)
$1 =  "\211\307???"


在C语言中,main函数的第二个参数不是char *,而是char **

(gdb) print (unsigned long long [4])*($rsi)
$8 = {140737488347644, 140737488347708, 140737488347714, 140737488347721}
(gdb) print (char[5])*(140737488347708)
$9 = "first"


现在,我们找到了参数,这些参数通过寄存器传递,就像在x86-64中的普通函数一样。

**结论:**正如我们所看到的,在使用C运行时的代码和不使用C运行时的代码之间,在传递命令行参数方面存在差异。

qoefvg9y

qoefvg9y2#

它看起来像3.4节 * 流程初始化 *,特别是图3.9,在已经提到的System V AMD64 ABI中准确地描述了您想要知道的内容。

3npbholx

3npbholx3#

我相信你需要做的是检查x86-64 ABI。具体来说,我认为您需要查看3.2.3节参数传递。

相关问题