Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
x86_64汇编Linux系统调用混乱_Linux_Assembly_X86 64_System Calls_Gnu Assembler - Fatal编程技术网

x86_64汇编Linux系统调用混乱

x86_64汇编Linux系统调用混乱,linux,assembly,x86-64,system-calls,gnu-assembler,Linux,Assembly,X86 64,System Calls,Gnu Assembler,我目前正在学习Linux上的汇编语言。我一直在使用《从头开始编程》一书,所有的例子都是32位的。我的操作系统是64位的,我一直在尝试用64位来做所有的例子。然而,我遇到了麻烦: .section .data .section .text .global _start _start: movq $60, %rax movq $2, %rbx int $0x80 这只是调用Linux退出系统调用,或者应该调用。相反,它会导致SEG故障,当我这样做时 .section .data .sectio

我目前正在学习Linux上的汇编语言。我一直在使用《从头开始编程》一书,所有的例子都是32位的。我的操作系统是64位的,我一直在尝试用64位来做所有的例子。然而,我遇到了麻烦:

.section .data

.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rbx
int $0x80
这只是调用Linux退出系统调用,或者应该调用。相反,它会导致SEG故障,当我这样做时

.section .data

.section .text
.global _start
_start:
movq $1, %rax
movq $2, %rbx
int $0x80
它起作用了。显然,问题是我移动到%rax的值。我在第二个示例中使用的值$1是“从头开始编程”所说的使用值,但是互联网上的多个来源都说64位系统调用号是$60。 我做错了什么?还有什么其他问题我应该注意,我应该用什么作为参考?以防万一,你需要知道,我正在读《从头开始编程》的第5章。

请阅读此文

请注意,在x64系统上对syscall使用
int0x80
,这是一个旧的兼容层。您应该在x64系统上使用
syscall
指令


您仍然可以使用这种旧方法,但您需要在x86模式下编译二进制文件,有关详细信息,请参阅编译器/汇编程序手册。

您在i386和x86\u 64之间遇到了一个惊人的差异:它们不使用相同的系统调用机制。正确的代码是:

movq $60, %rax
movq $2,  %rdi   ; not %rbx!
syscall
中断
0x80
始终调用32位系统调用。它允许32位应用程序在64位系统上运行


出于学习的目的,您可能应该严格按照教程进行操作,而不是将其转换为64位—您可能会遇到一些其他显著的行为差异。一旦熟悉了i386,就可以分别学习x86_64。

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
退出对应于
1
,但在
/usr/include/asm/unistd_64.h
退出对应于
60
正确地指出,64位x86 Linux与32位Linux的系统调用机制不同

然而,由于以下几个原因,该答案不完整且具有误导性:

  • 这一变化实际上是在64位系统流行之前引入的,其动机是。Linus Torvalds(在奔腾Pro时代由英特尔推出,但有缺陷,没有实际好处)。因此,现代32位Linux系统实际上使用的是
    syscenter
    ,而不是
    int0x80
  • 64位x86 Linux内核实际上不使用
    SYSENTER
    SYSEXIT
    。它们使用非常相似的
    SYSCALL
    /
    SYSRET
    指令
正如所述,
SYSENTER
实际上不适用于许多64位Linux系统,即64位AMD系统

无可否认,这是一个令人困惑的局面。问题是,但归根结底是:

对于32位内核,SYSENTER/SYSEXIT是[AMD和Intel CPU之间]唯一的兼容对

仅对于长模式下的64位内核…SYSCALL/SYSRET是[AMD和Intel CPU之间]唯一的兼容对

似乎在64位模式的英特尔CPU上,您可以不用使用
syscenter
,因为它与
SYSCALL
的功能相同,但AMD系统并非如此


底线:在64位x86系统上的Linux上始终使用
SYSCALL
。这是x86-64 ABI实际指定的。(更多详细信息,请参见此页。)

我可能最终会这么做。感谢您的回复。第一个系统调用参数应该使用
%rdi
,而不是
%rbx
。感谢您捕获该参数-已修复。
syscenter
在我的系统上不起作用。正确的指令是
syscall
@hpsMouse,
syscall
是源于AMD的版本,而
syscenter
是源于Intel的版本。这里有更多细节:我也在做《shellcoder手册2》中的东西。不过,我的操作系统也是64位的。我使用nasm选项-f elf32组装,我还使用-melf_i386链接。我使用gdb和evans调试器(但是,错误,它是为64编译的,并且在加载二进制文件后会提示,但在edb内部、gdb内部和执行中,错误是相同的):int 0x80之后的指令后出现SEGFULT。我只想退出。我已经看到,(r)ax寄存器必须包含0x3c而不是0x01(因为使用了64位的syscall文件),但我无法想象,为什么调用int 0x80之后的指令。有人知道,为什么吗?很高兴看到有人指出x86_64 Linux实际上使用的是
syscall
而不是
sysenter
!我写了一个。基本上是重复的:-
int$0x80
仍然调用32位ABI,使用32位寄存器和调用号。真的只是用于学习32位教程。我的理解是,现代AMD CPU支持从32位用户空间(进入64位内核)进入的
syscenter
。但在任何情况下,都不应直接使用
sysenter
;它没有官方支持。对于简单的初学者代码,可以使用
int$0x80
,或者
call
到VDSO中,让内核提供的代码运行
sysenter
,或者在CPU上运行效率最高的任何东西。是的,
int 0x80
始终使用unistd_32个呼叫号码(和32位寄存器)。只有64位的
syscall