FreeBSD/amd64 程序集 - 如何从 _start 读取“ARGC”?

tim*_*may 6 assembly freebsd x86-64 abi argc

argc有时返回正确的值,有时返回 0,有时返回(看似)随机数……所有这些都来自同一个可执行文件。

.section .text
.global _start
_start:
    movq    $1, %rax
    popq    %rdi
    syscall
Run Code Online (Sandbox Code Playgroud)

例如:

%as -o this.o this.s ; ld -o this this.o

%./this; echo $?
1

%./this 1; echo $?
0

%./this 1 2; echo $?
3

%./this 1 2 a; echo $?
4

%./this 1 2 a f; echo $?
0

%_
Run Code Online (Sandbox Code Playgroud)

我对汇编有点陌生,但我非常有信心获取参数计数就像在 Linux 中将其从堆栈中弹出一样简单,其中 System V ABI 记录 RSP 在argcexecve进程中指向的内容。

是我做错了什么,还是事情真的很糟糕?

小智 5

我在 FreeBSD 9.0/amd64 上遇到同样的情况感到困惑。我所做的是(我使用 nasm 进行汇编):

$ cat foo.asm
global _start
_start:
        mov     rax, 4          ; write
        mov     rdi, 1          ; stdout
        mov     rsi, rsp        ; address
        mov     rdx, 16         ; 16bytes
        syscall

        mov     rax, 1          ; exit
        syscall
$ nasm -f elf64 foo.asm && ld -o foo foo.o
$ ./foo | hd
00000000  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................|
00000010
$ ./foo 2 | hd
00000000  02 00 00 00 00 00 00 00  b8 dc ff ff ff 7f 00 00  |................|
00000010
$ ./foo 2 3 | hd
00000000  00 00 00 00 00 00 00 00  03 00 00 00 00 00 00 00  |................|
00000010
$ ./foo 2 3 4 | hd
00000000  00 00 00 00 00 00 00 00  04 00 00 00 00 00 00 00  |................|
00000010
$ ./foo 2 3 4 5 | hd
00000000  05 00 00 00 00 00 00 00  b0 dc ff ff ff 7f 00 00  |................|
00000010
Run Code Online (Sandbox Code Playgroud)

我预计 argc 位于 rsp,但事实并非如此。

我猜测内核(图像激活器)设置了寄存器。我搜索了源代码树,在 /usr/src/sys/amd64/amd64/machdep.c (exec_setregs) 中找到了以下代码。

        regs->tf_rsp = ((stack - 8) & ~0xFul) + 8;
        regs->tf_rdi = stack;           /* argv */
Run Code Online (Sandbox Code Playgroud)

编辑:machdep.c 已被拆分,现在可以在 exec_machdep.c 中找到该函数

这些行看起来表明 rsp 已对齐,实际数据位于 rdi。我更改了代码,并得到了预期的结果。

$ cat foo.asm
global _start
_start:
        push    rdi
        mov     rax, 4          ; write
        mov     rdi, 1          ; stdout
        pop     rsi
        mov     rdx, 16         ; 16bytes
        syscall

        mov     rax, 1          ; exit
        syscall
$ nasm -f elf64 foo.asm && ld -o foo foo.o
$ ./foo | hd
00000000  01 00 00 00 00 00 00 00  b0 dc ff ff ff 7f 00 00  |................|
00000010
$ ./foo 2 | hd
00000000  02 00 00 00 00 00 00 00  a8 dc ff ff ff 7f 00 00  |................|
00000010
$ ./foo 2 3 | hd
00000000  03 00 00 00 00 00 00 00  a8 dc ff ff ff 7f 00 00  |................|
00000010
$ ./foo 2 3 4 | hd
00000000  04 00 00 00 00 00 00 00  a8 dc ff ff ff 7f 00 00  |................|
00000010
$ ./foo 2 3 4 5 | hd
00000000  05 00 00 00 00 00 00 00  a8 dc ff ff ff 7f 00 00  |................|
00000010
Run Code Online (Sandbox Code Playgroud)

你可以试试rdi吗?