Ziemlich viel hat sich zwischen i386 und x86_64 geändert, einschließlich sowohl der Anweisung, die verwendet wird, um in den Kernel zu gehen, als auch der Register, die verwendet werden, um Systemaufrufargumente zu übertragen. Hier ist Code, der Ihrem entspricht:
.section .data
.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rdi
syscall
Zitieren aus dieser Antwort auf eine verwandte Frage:
Die Syscall-Nummern befinden sich im Linux-Quellcode unter arch/x86/include/asm/unistd_64.h. Die Syscall-Nummer wird im rax-Register übergeben. Die Parameter sind in rdi, rsi, rdx, r10, r8, r9. Der Aufruf wird mit der Anweisung "syscall" aufgerufen. Der Syscall überschreibt das rcx-Register. Die Rendite ist in Rax.
Sie stoßen auf einen überraschenden Unterschied zwischen i386 und x86_64:Sie verwenden nicht denselben Systemaufrufmechanismus. Der richtige Code lautet:
movq $60, %rax
movq $2, %rdi ; not %rbx!
syscall
Unterbrechen Sie 0x80
ruft immer 32-Bit-Systemaufrufe auf. Es wird verwendet, damit 32-Bit-Anwendungen auf 64-Bit-Systemen ausgeführt werden können.
Zum Zwecke des Lernens sollten Sie wahrscheinlich versuchen, dem Tutorial genau zu folgen, anstatt spontan in 64-Bit zu übersetzen – es gibt einige andere signifikante Verhaltensunterschiede, auf die Sie wahrscheinlich stoßen werden. Sobald Sie mit i386 vertraut sind, dann Sie können x86_64 separat erwerben.
Bitte lesen Sie dies Was sind die Aufrufkonventionen für UNIX- und Linux-Systemaufrufe auf x86-64
und beachten Sie, dass die Verwendung von int 0x80
für syscall auf x64-Systemen ist eine alte Kompatibilitätsschicht. Sie sollten syscall
verwenden Anleitung auf x64-Systemen.
Sie können diese alte Methode immer noch verwenden, aber Sie müssen Ihre Binärdateien in einem x86-Modus kompilieren, siehe Ihr Compiler-/Assembler-Handbuch für Details.
Die Antwort von Duskwuff weist richtig darauf hin, dass der Mechanismus für Systemaufrufe für 64-Bit-x86-Linux anders ist als für 32-Bit-Linux.
Diese Antwort ist jedoch aus mehreren Gründen unvollständig und irreführend:
- Die Änderung wurde tatsächlich eingeführt, bevor 64-Bit-Systeme populär wurden , motiviert durch die Beobachtung, dass
int 0x80
war auf Pentium 4 sehr langsam. Linus Torvalds hat eine Lösung mitSYSENTER
codiert /SYSEXIT
Anweisungen (die von Intel um die Pentium Pro-Ära herum eingeführt wurden, aber fehlerhaft waren und keinen praktischen Nutzen brachten). Moderne 32-Bit-Linux-Systeme verwenden also tatsächlichSYSENTER
, nichtint 0x80
. - 64-Bit-x86-Linux-Kernel verwenden eigentlich nicht
SYSENTER
undSYSEXIT
. Sie verwenden tatsächlich den sehr ähnlichenSYSCALL
/SYSRET
Anleitung.
Wie in den Kommentaren erwähnt, SYSENTER
funktioniert nicht wirklich auf vielen 64-Bit-Linux-Systemen – nämlich 64-Bit AMD Systeme.
Es ist eine zugegebenermaßen verwirrende Situation. Die blutigen Details sind hier, aber es läuft darauf hinaus:
Für einen 32-Bit-Kernel sind SYSENTER/SYSEXIT das einzige kompatible Paar [zwischen AMD- und Intel-CPUs]
Nur für einen 64-Bit-Kernel im Long-Modus … SYSCALL/SYSRET sind das einzige kompatible Paar [zwischen AMD- und Intel-CPUs]
Es scheint, dass auf einem Intel CPU im 64-Bit-Modus können Sie mit SYSENTER
davonkommen weil es dasselbe tut wie SYSCALL
, dies gilt jedoch nicht für AMD-Systeme.
Fazit:Immer SYSCALL
verwenden unter Linux auf 64-Bit-x86-Systemen . Es ist das, was die x86-64-ABI tatsächlich angibt. (Siehe diese großartige Wiki-Antwort für noch mehr Details.)