![](/img/trans.png)
[英]Linux Assembly x86_64 create a file using command line parameters
[英]Linux 64 command line parameters in Assembly
此描述适用于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 ... ... }
看起来参数在堆栈上。 由于此代码不清楚,我问这个问题。 我猜我可以将rp保留在rbp中,然后使用0(%rbp),8(%rbp),16(%rbp)等来访问这些参数。这是正确的吗?
尽管接受的答案绰绰有余,但我想给出一个明确的答案,因为还有一些其他答案可能会引起混淆。
最重要的(有关更多信息,请参见下面的示例):在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
,包装命令行参数并将main
作为公共函数调用。 为了看到它,让我们考虑以下示例。
没有C运行时/ GCC与-nostdlib
让我们检查一下这个简单的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代码的代码之间传递命令行参数是有区别的。
看起来像3.4 流程初始化 ,特别是图3.9,在已经提到过的System V中,AMD64 ABI正好描述了你想知道的内容。
我相信你需要做的就是查看x86-64 ABI 。 具体来说,我认为你需要看看3.2.3参数传递。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.