gcc – 退出系统调用的正确常量是多少?

我正在尝试学习x86_64程序集,并使用GCC作为我的汇编程序.我正在使用的确切命令是:

gcc -nostdlib tapydn.S -D__ASSEMBLY__

我主要使用gcc作为预处理器.这是tapydn.S:

.global _start

#include <asm-generic/unistd.h>

syscall=0x80

.text
_start:
    movl $__NR_exit, %eax
    movl $0x00, %ebx
    int  $syscall

这导致分段错误.我认为问题出在以下几行:

 movl $__NR_exit, %eax

我使用了__NR_exit,因为它比一些幻数更具描述性.但是,似乎我对它的使用是不正确的.我相信这是因为当我将有问题的行更改为以下内容时,它运行良好:

movl $0x01, %eax

进一步备份这一思路是usr / include / asm-generic / unistd.h的内容:

#define __NR_exit 93
__SYSCALL(__NR_exit, sys_exit)

我期望__NR_exit的值为1,而不是93!显然,我误解了它的目的并因此误用了它.据我所知,我很幸运,$0x01的情况正常工作(很像C中未定义的行为),所以我一直在挖……

接下来,我查找了sys_exit的定义.我找不到它.我尝试使用它如下(有和没有前面的$):

movl $sys_exit, %eax

这不会链接:

/tmp/cc7tEUtC.o: In function `_start':
(.text+0x1): undefined reference to `sys_exit'
collect2: error: ld returned 1 exit status

我的猜测是它是一个系统库中的符号而我没有链接它,因为我将-nostdlib传递给了GCC.如果可能的话,我想避免将这么大的库链接到一个符号.

为了回应Jester关于混合32位和64位常量的评论,我尝试使用值0x3C,如下所示:

movq $0x3C, %eax
movq $0x00, %ebx

这也导致了分段错误.我也试过换掉rax和rbx的eax和ebx:

movq $0x3C, %rax
movq $0x00, %rbx

分段错误仍然存​​在.

然后Jester评论说我应该使用syscall而不是int $0x80:

.global _start

#include <asm-generic/unistd.h>

.text
_start:
    movq $0x3C, %rax
    movq $0x00, %rbx
    syscall

这有效,但我后来被告知我应该按照System V AMD64 ABI使用rdi而不是rbx:

movq $0x00, %rdi

这也可以正常工作,但最终仍然使用幻数0x3C作为系统调用号码.

总结一下,我的问题如下:

> __NR_exit的正确用法是什么?
>我应该使用什么来代替退出系统调用的幻数?

最佳答案 获取系统调用号的正确头文件是sys / syscall.h.常量称为SYS _ ###,其中###是您感兴趣的系统调用的名称.__ NS _ ###宏是实现细节,不应使用.根据经验,如果标识符以下划线开头,则不应使用它,如果它以2开头,则绝对不应使用.参数进入rdi,rsi,rdx,r10,r8和r9.这是一个Linux示例程序:

#include <sys/syscall.h>

    .globl _start
_start:
    mov $SYS_exit,%eax
    xor %edi,%edi
    syscall

这些约定大多可以移植到其他类UNIX操作系统.

点赞