我目前正在学习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值是“从头开始编程”所说的,但互联网上有多个来源说64位系统呼叫号码是60美元。 Reference 我究竟做错了什么?还应该注意哪些其他问题以及我应该使用什么作为参考?万一你需要知道,我在第5章“从头开始编程”。
答案 0 :(得分:17)
你在i386和x86_64之间遇到了一个令人惊讶的区别:他们没有使用相同的系统调用机制。正确的代码是:
movq $60, %rax
movq $2, %rdi ; not %rbx!
syscall
中断0x80
始终调用32位系统调用。它用于允许32位应用程序在64位系统上运行。
出于学习的目的,您可能应该尝试完全遵循教程,而不是动态地转换为64位 - 还有一些其他重要的行为差异,您可能会遇到这些差异。一旦熟悉了i386,然后,你就可以单独拿起x86_64了。
答案 1 :(得分:12)
请阅读此What are the calling conventions for UNIX & Linux system calls on x86-64
并注意在x64系统上使用int 0x80
进行系统调用是一个旧的兼容性层。你应该在x64系统上使用syscall
指令。
您仍然可以使用这个旧方法,但是您需要在x86模式下编译二进制文件,有关详细信息,请参阅编译器/汇编程序手册。
答案 2 :(得分:7)
duskwuff的answer指出正确的系统调用机制对于64位x86 Linux与32位Linux不同。
然而,由于以下几个原因,这个答案是不完整和误导的:
int 0x80
was very slow on Pentium 4推动。 Linus Torvalds coded up a solution using the SYSENTER
/SYSEXIT
instructions(英特尔在Pentium Pro时代推出了这款产品,但这些产品都是有缺陷的,并没有带来任何实际好处)。所以现代32位Linux系统实际上使用的是SYSENTER
,而不是int 0x80
。SYSENTER
和SYSEXIT
。他们actually use非常相似的SYSCALL
/ SYSRET
说明。作为pointed out in the comments,SYSENTER
实际上并不适用于许多64位Linux系统 - 即64位 AMD < / strong>系统。
这是一个令人困惑的情况。 gory details are here,但它归结为:
对于32位内核,SYSENTER / SYSEXIT是唯一的兼容对 [在AMD和Intel CPU之间]
仅适用于长模式的64位内核... SYSCALL / SYSRET是唯一的兼容对 [在AMD和Intel CPU之间]
似乎在64位模式的 Intel CPU上,您可以使用SYSENTER
,因为它与SYSCALL
完全相同,但这是不是AMD系统的情况。
底线:在64位x86系统上的Linux上始终使用SYSCALL
。这就是x86-64 ABI实际指定的内容。 (有关详细信息,请参阅此wiki answer。)
答案 3 :(得分:4)
在i386和x86_64之间发生了很多变化,包括用于进入内核的指令和用于承载系统调用参数的寄存器。这是与你的代码相当的代码:
.section .data
.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rdi
syscall
从this answer引用相关问题:
系统调用号位于arch / x86 / include / asm / unistd_64.h下的Linux源代码中。系统调用号在rax寄存器中传递。参数在rdi,rsi,rdx,r10,r8,r9中。使用“syscall”指令调用该调用。系统调用会覆盖rcx寄存器。回报是rax。
答案 4 :(得分:2)
如果您检查/usr/include/asm/unistd_32.h
退出对应于1
但是在
/usr/include/asm/unistd_64.h
退出对应60
。