GNU/Linux >> LINUX-Kenntnisse >  >> Linux

x86_64 Assembly Linux-Systemaufruf-Verwirrung

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 mit SYSENTER 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ächlich SYSENTER , nicht int 0x80 .
  • 64-Bit-x86-Linux-Kernel verwenden eigentlich nicht SYSENTER und SYSEXIT . Sie verwenden tatsächlich den sehr ähnlichen SYSCALL /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.)


Linux
  1. Linux – Aufrufmethoden für Systemaufrufe im neuen Kernel?

  2. Best Practices für die Programmierung von Linux-Systemen in C-Sprache – Teil 1

  3. Linux-Systemaufruftabelle oder Cheatsheet für Assembly

  4. Wie rufe ich einen Systemaufruf über Syscall oder Sysenter in der Inline-Assembly auf?

  5. Schnellster Linux-Systemaufruf

Kali Linux-Systemanforderungen

Befehl zum Herunterfahren von Linux

Fsck-Befehl unter Linux

Ist Linux ein Betriebssystem oder ein Kernel?

Dokumentieren der Systemverfügbarkeit in Linux

Wie kann ich überprüfen, ob das Linux-System 32-Bit oder 64-Bit ist?