我正在尝试学习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操作系统.