我正在尝试学习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
这也导致了分段错误。我还尝试为eax
和ebx
换取rax
和rbx
:
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
的正确用法是什么?exit
系统调用的幻数?答案 0 :(得分:1)
获取系统调用号的正确头文件是sys/syscall.h
。常量称为SYS_###
,其中###
是您感兴趣的系统调用的名称。__NR_###
宏是实现细节,不应使用。根据经验,如果标识符以下划线开头,则不应使用它,如果它以2开头,则绝对不应使用。参数分为rdi
,rsi
,rdx
,r10
,r8
和r9
。这是Linux的示例程序:
#include <sys/syscall.h>
.globl _start
_start:
mov $SYS_exit,%eax
xor %edi,%edi
syscall
这些约定大多可以移植到其他类UNIX操作系统。