此描述适用于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)等访问这些参数。这是正确的吗?
答案 0 :(得分:9)
看起来第3.4节流程初始化,特别是图3.9,在已经提到的System V AMD64 ABI中准确描述了您想知道的内容。
答案 1 :(得分:8)
尽管已接受的答案绰绰有余,但我想给出一个明确的答案,因为还有其他一些答案可能会引起混淆。
最重要的(有关更多信息,请参阅下面的示例):在x86-64中,命令行参数通过堆栈传递:
public interface IHasPredicateGetter<T> {
[NotNull] Expression<Func<T, bool>> GetPredicateFromString([NotNull] string pValue);
}
public class Movie : IHasPredicateGetter<Movie> {
public int ID { get; set; }
public string Name { get; set; }
public Expression<Func<Movie, bool>> GetPredicateFromString(string pValue) {
return m => m.Name.Contains(pValue);
}
}
它与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 ...
,%rdi
等等。
还有一件事:不应该推断出C %rsi
- 函数的逆向工程行为。 C运行时提供入口点main
,包装命令行参数并调用_start
作为常用函数。为了看到它,让我们考虑以下示例。
没有C运行时/ GCC与-nostdlib
让我们检查一下这个简单的x86-64汇编程序,它只返回42:
main
我们用以下方式构建它:
.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
使用
在gdb中运行gcc -nostdlib exit64.s -o exit64
并停在./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
。接下来的4个值看起来很像指针。让我们看看第二个指针:
argc
正如预期的那样,它是第一个命令行参数。
因此有实验证据表明命令行参数是通过x86-64中的堆栈传递的。但是,只有通过阅读ABI(如建议的接受答案),我们才能确定,情况确实如此。
使用C运行时
我们必须稍微更改程序,将(gdb) print (char[5])*(140737488347711)
$1 = "first"
重命名为_start
,因为入口点main
由C运行时提供。
_start
我们构建它(默认情况下使用C运行时):
.section .text
.globl main
main:
movq $60, %rax #60 -> exit
movq $42, %rdi #return 42
syscall #run kernel
使用
在gdb中运行gcc exit64gcc.s -o exit64gcc
并停在./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
但等等,C中(gdb) print (char[5])*($rsi)
$1 = "\211\307???"
函数的第二个参数不是main
,而char *
也是:
char **
现在我们找到了我们的参数,这些参数通过寄存器传递,就像x86-64中的普通函数一样。
<强>结论:强> 正如我们所看到的,关于在使用C运行时的代码和不执行C代码的代码之间传递命令行参数是有区别的。
答案 2 :(得分:1)
我相信你需要做的就是查看x86-64 ABI。具体来说,我认为你需要看看3.2.3参数传递。