简体   繁体   English

程序集中的Linux 64命令行参数

[英]Linux 64 command line parameters in Assembly

This description is valid for Linux 32 bit: When a Linux program begins, all pointers to command-line arguments are stored on the stack. 此描述适用于Linux 32位:当Linux程序开始时,所有指向命令行参数的指针都存储在堆栈中。 The number of arguments is stored at 0(%ebp), the name of the program is stored at 4(%ebp), and the arguments are stored from 8(%ebp). 参数的数量存储在0(%ebp),程序的名称存储在4(%ebp),参数存储在8(%ebp)。

I need the same information for 64 bit. 64位需要相同的信息。

Edit: I have working code sample which shows how to use argc, argv[0] and argv[1]: http://cubbi.com/fibonacci/asm.html 编辑:我有工作代码示例,演示如何使用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 ...
...
}

It looks like parameters are on the stack. 看起来参数在堆栈上。 Since this code is not clear, I ask this question. 由于此代码不清楚,我问这个问题。 My guess that I can keep rsp in rbp, and then access these parameters using 0(%rbp), 8(%rbp), 16(%rbp) etc. It this correct? 我猜我可以将rp保留在rbp中,然后使用0(%rbp),8(%rbp),16(%rbp)等来访问这些参数。这是正确的吗?

Despite the accepted answer being more than sufficient, I would like to give an explicit answer, as there are some other answers which might confuse. 尽管接受的答案绰绰有余,但我想给出一个明确的答案,因为还有一些其他答案可能会引起混淆。

Most important (for more information see examples below): in x86-64 the command line arguments are passed via stack: 最重要的(有关更多信息,请参见下面的示例):在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 ...

It is different from the function parameter passing in x86-64, which uses %rdi , %rsi and so on. 它与x86-64中传递的函数参数不同,后者使用%rdi%rsi等。

One more thing: one should not deduce the behavior from reverse engineering of the C main -function. 还有一件事:不应该从C main函数的逆向工程中推断出行为。 C runtime provides the entry point _start , wraps the command line arguments and calls main as a common function. C运行时提供入口点_start ,包装命令行参数并将main作为公共函数调用。 To see it, let's consider the following example. 为了看到它,让我们考虑以下示例。

No C runtime/GCC with -nostdlib 没有C运行时/ GCC与-nostdlib

Let's check this simple x86-64 assembler program, which do nothing but returns 42: 让我们检查一下这个简单的x86-64汇编程序,它只返回42:

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

We build it with: 我们建立它:

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

or with 或者

gcc -nostdlib exit64.s -o exit64

run in gdb with 用gdb运行

./exit64 first second third

and stop at the breakpoint at _start . 并停在_start的断点处。 Let's check the registers: 我们来看看寄存器:

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

Nothing there. 那里空无一物。 What about the stack? 堆栈怎么样?

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

So the first element on the stack is 4 - the expected argc . 所以堆栈中的第一个元素是4 - 预期的argc The next 4 values look a lot like pointers. 接下来的4个值看起来很像指针。 Let's look at the second pointer: 让我们看看第二个指针:

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

As expected it is the first command line argument. 正如预期的那样,它是第一个命令行参数。

So there is experimental evidence, that the command line arguments are passed via stack in x86-64. 因此有实验证据表明命令行参数是通过x86-64中的堆栈传递的。 However only by reading the ABI (as the accepted answer suggested) we can be sure, that this is really the case. 但是,只有通过阅读ABI (作为接受的答案建议),我们可以肯定,情况确实如此。

With C runtime 使用C运行时

We have to change the program slightly, renaming _start into main , because the entry point _start is provided by the C runtime. 我们必须稍微更改程序,将_start重命名为main ,因为入口点_start由C运行时提供。

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

We build it with (C runtime is used per default): 我们用它构建它(默认情况下使用C运行时):

gcc exit64gcc.s -o exit64gcc

run in gdb with 用gdb运行

./exit64gcc first second third

and stop at the breakpoint at main . 并停在main断点处。 What is at the stack? 什么在堆栈?

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

It does not look familiar. 它看起来并不熟悉。 And registers? 和寄存器?

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

We can see that rdi contains the argc value. 我们可以看到rdi包含argc值。 But if we now inspect the pointer in rsi strange things happen: 但是如果我们现在检查rsi的指针,就会发生奇怪的事情:

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

But wait, the second argument of the main function in C is not char * , but char ** also: 但是等一下,C中main函数的第二个参数不是char * ,而char **也是:

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

And now we found our arguments, which are passed via registers as it would be for a normal function in x86-64. 现在我们找到了我们的参数,这些参数通过寄存器传递,就像x86-64中的普通函数一样。

Conclusion: As we can see, the is a difference concerning passing of command line arguments between code using C runtime and code which doesn't. 结论:正如我们所看到的,关于在使用C运行时的代码和不执行C代码的代码之间传递命令行参数是有区别的。

看起来像3.4 流程初始化 ,特别是图3.9,在已经提到过的System V中,AMD64 ABI正好描述了你想知道的内容。

I do believe what you need to do is check out the x86-64 ABI . 我相信你需要做的就是查看x86-64 ABI Specifically, I think you need to look at section 3.2.3 Parameter Passing. 具体来说,我认为你需要看看3.2.3参数传递。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM