Beaucoup de choses ont changé entre i386 et x86_64, y compris à la fois l'instruction utilisée pour entrer dans le noyau et les registres utilisés pour transporter les arguments d'appel système. Voici un code équivalent au vôtre :
.section .data
.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rdi
syscall
Citant cette réponse à une question connexe :
Les numéros d'appel système se trouvent dans le code source Linux sous arch/x86/include/asm/unistd_64.h. Le numéro d'appel système est passé dans le registre rax. Les paramètres sont en rdi, rsi, rdx, r10, r8, r9. L'appel est invoqué avec l'instruction "syscall". L'appel système écrase le registre rcx. Le retour est en rax.
Vous rencontrez une différence surprenante entre i386 et x86_64 :ils n'utilisent pas le même mécanisme d'appel système. Le bon code est :
movq $60, %rax
movq $2, %rdi ; not %rbx!
syscall
Interrompre 0x80
appelle toujours les appels système 32 bits. Il est utilisé pour permettre aux applications 32 bits de s'exécuter sur des systèmes 64 bits.
À des fins d'apprentissage, vous devriez probablement essayer de suivre exactement le didacticiel, plutôt que de traduire à la volée en 64 bits - il existe quelques autres différences de comportement importantes que vous risquez de rencontrer. Une fois que vous êtes familiarisé avec i386, alors vous pouvez récupérer x86_64 séparément.
veuillez lire ceci Quelles sont les conventions d'appel pour les appels système UNIX et Linux sur x86-64
et notez que l'utilisation de int 0x80
pour syscall sur les systèmes x64 est une ancienne couche de compatibilité. vous devez utiliser syscall
instructions sur les systèmes x64.
vous pouvez toujours utiliser cette ancienne méthode, mais vous devez compiler vos binaires en mode x86, consultez le manuel de votre compilateur/assembleur pour plus de détails.
La réponse de duskwuff indique correctement que le mécanisme des appels système est différent pour Linux x86 64 bits par rapport à Linux 32 bits.
Cependant, cette réponse est incomplète et trompeuse pour plusieurs raisons :
- Le changement a en fait été introduit avant que les systèmes 64 bits ne deviennent populaires , motivé par le constat que
int 0x80
était très lent sur Pentium 4. Linus Torvalds a codé une solution en utilisant leSYSENTER
/SYSEXIT
instructions (qui avaient été introduites par Intel à l'époque du Pentium Pro, mais qui étaient boguées et n'offraient aucun avantage pratique). Donc les systèmes Linux 32 bits modernes utilisent en faitSYSENTER
, pasint 0x80
. - Les noyaux Linux x86 64 bits n'utilisent pas réellement
SYSENTER
etSYSEXIT
. Ils utilisent en fait le très similaireSYSCALL
/SYSRET
instructions.
Comme indiqué dans les commentaires, SYSENTER
ne fonctionne pas réellement sur de nombreux systèmes Linux 64 bits —à savoir AMD 64 bits systèmes.
C'est une situation certes déroutante. Les détails sanglants sont ici, mais cela revient à ceci :
Pour un noyau 32 bits, SYSENTER/SYSEXIT sont le seul couple compatible [entre les CPU AMD et Intel]
Pour un noyau 64 bits en mode Long uniquement… SYSCALL/SYSRET sont le seul couple compatible [entre les CPU AMD et Intel]
Il semble que sur un Intel CPU en mode 64 bits, vous pouvez vous en sortir en utilisant SYSENTER
car il fait la même chose que SYSCALL
, cependant ce n'est pas le cas pour les systèmes AMD.
Conclusion :utilisez toujours SYSCALL
sous Linux sur des systèmes x86 64 bits . C'est ce que spécifie réellement l'ABI x86-64. (Voir cette excellente réponse wiki pour encore plus de détails.)