![](/img/trans.png)
[英]Writing a putchar in Assembly for x86_64 with 64 bit Linux?
[英]x86_64 Assembly Linux System Call Confusion
我目前正在 Linux 上学习汇编语言。 我一直在使用“从头开始编程”这本书,所有的例子都是 32 位的。 我的操作系统是 64 位的,我一直在尝试用 64 位来做所有的例子。 但是,我遇到了麻烦:
.section .data
.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rbx
int $0x80
这只是调用 Linux 退出系统调用或者它应该调用。 相反,它会导致 SEG FAULT,而当我这样做时
.section .data
.section .text
.global _start
_start:
movq $1, %rax
movq $2, %rbx
int $0x80
有用。 显然问题是我移动到 %rax 的值。 我在第二个示例中使用的值 $1 是“从头开始编程”所说的使用值,但是 Internet 上的多个来源表示 64 位系统调用号是 $60。 参考我做错了什么? 另外我应该注意哪些其他问题以及我应该使用什么作为参考? 以防万一你需要知道,我在从头开始编程的第 5 章。
您在 i386 和 x86_64 之间遇到了一个令人惊讶的差异:它们不使用相同的系统调用机制。 正确的代码是:
movq $60, %rax
movq $2, %rdi ; not %rbx!
syscall
中断0x80
总是调用 32 位系统调用。 它用于允许 32 位应用程序在 64 位系统上运行。
出于学习目的,您可能应该尝试完全按照教程进行操作,而不是立即将其转换为 64 位——您可能会遇到其他一些重要的行为差异。 一旦你熟悉了 i386,那么你就可以单独拿起 x86_64。
请阅读此x86-64 上 UNIX 和 Linux 系统调用的调用约定是什么
请注意,在 x64 系统上使用int 0x80
进行系统调用是一个旧的兼容层。 您应该在 x64 系统上使用syscall
指令。
您仍然可以使用这种旧方法,但是您需要在 x86 模式下编译二进制文件,有关详细信息,请参阅您的编译器/汇编器手册。
duskwuff的回答正确地指出了 64 位 x86 Linux 与 32 位 Linux 的系统调用机制不同。
但是,由于以下几个原因,此答案不完整且具有误导性:
int 0x80
在 Pentium 4 上非常慢。 Linus Torvalds使用SYSENTER
/ SYSEXIT
指令编写了一个解决方案(英特尔在 Pentium Pro 时代引入了这些指令,但这些指令有问题并且没有实际好处)。 所以现代 32 位 Linux 系统实际上使用SYSENTER
,而不是int 0x80
。SYSENTER
和SYSEXIT
。 它们实际上使用非常相似的SYSCALL
/ SYSRET
指令。 正如评论中指出的那样, SYSENTER
实际上不适用于许多 64 位 Linux 系统——即64 位AMD系统。
这是一个公认的令人困惑的情况。 血腥的细节在这里,但归结为:
对于 32 位内核,SYSENTER/SYSEXIT 是唯一的兼容对[AMD 和 Intel CPU 之间]
仅对于长模式下的 64 位内核...... SYSCALL/SYSRET 是唯一兼容的对[AMD 和 Intel CPU 之间]
似乎在 64 位模式下的Intel CPU 上,您可以使用SYSENTER
因为它与SYSCALL
执行相同的SYSCALL
,但是对于 AMD 系统,情况并非如此。
底线:始终在 64 位 x86 系统上的 Linux 上使用SYSCALL
。 这是 x86-64 ABI 实际指定的内容。 (有关更多详细信息,请参阅这个很棒的wiki 答案。)
i386 和 x86_64 之间发生了很多变化,包括用于进入内核的指令和用于携带系统调用参数的寄存器。 这是与您的代码等效的代码:
.section .data
.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rdi
syscall
引用这个对相关问题的回答:
系统调用号位于 arch/x86/include/asm/unistd_64.h 下的 Linux 源代码中。 系统调用号在 rax 寄存器中传递。 参数在rdi、rsi、rdx、r10、r8、r9中。 使用“syscall”指令调用该调用。 系统调用会覆盖 rcx 寄存器。 回报是 rax。
如果您检查/usr/include/asm/unistd_32.h
exit 对应于1
但在/usr/include/asm/unistd_64.h
exit 对应于60
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.