Mezi i386 a x86_64 se toho změnilo docela dost, včetně instrukce používané pro vstup do jádra a registrů používaných k přenášení argumentů systémových volání. Zde je kód ekvivalentní vašemu:
.section .data
.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rdi
syscall
Cituji z této odpovědi na související otázku:
Čísla systémových volání jsou ve zdrojovém kódu Linuxu pod arch/x86/include/asm/unistd_64.h. Číslo syscall je předáno v registru rax. Parametry jsou v rdi, rsi, rdx, r10, r8, r9. Volání je vyvoláno instrukcí "syscall". Systémové volání přepíše registr rcx. Návratnost je v rax.
Narážíte na jeden překvapivý rozdíl mezi i386 a x86_64:nepoužívají stejný mechanismus systémových volání. Správný kód je:
movq $60, %rax
movq $2, %rdi ; not %rbx!
syscall
Přerušení 0x80
vždy vyvolá 32bitová systémová volání. Používá se k tomu, aby 32bitové aplikace mohly běžet na 64bitových systémech.
Pro účely učení byste se pravděpodobně měli pokusit přesně postupovat podle návodu, spíše než překládat za běhu do 64bitové verze – existuje několik dalších významných rozdílů v chování, na které pravděpodobně narazíte. Až se seznámíte s i386, pak x86_64 si můžete vyzvednout samostatně.
přečtěte si prosím toto Jaké jsou konvence volání pro systémová volání UNIX a Linux na x86-64
a všimněte si, že pomocí int 0x80
pro syscall na systémech x64 je stará vrstva kompatibility. měli byste použít syscall
instrukce pro systémy x64.
stále můžete používat tuto starou metodu, ale musíte své binární soubory zkompilovat v režimu x86, podrobnosti najdete v příručce ke kompilátoru/assembleru.
Odpověď duskwuff správně poukazuje na to, že mechanismus systémových volání se liší pro 64bitový x86 Linux a 32bitový Linux.
Tato odpověď je však neúplná a zavádějící z několika důvodů:
- Změna byla ve skutečnosti představena předtím, než se 64bitové systémy staly populární , motivováno pozorováním, že
int 0x80
byl na Pentiu 4 velmi pomalý. Linus Torvalds kódoval řešení pomocíSYSENTER
/SYSEXIT
instrukce (které byly představeny Intelem kolem éry Pentium Pro, ale které byly chybné a nepřinášely žádnou praktickou výhodu). Takže moderní 32bitové systémy Linux ve skutečnosti používajíSYSENTER
, nikoliint 0x80
. - 64bitová jádra x86 Linux ve skutečnosti nepoužívají
SYSENTER
aSYSEXIT
. Ve skutečnosti používají velmi podobnýSYSCALL
/SYSRET
pokyny.
Jak je uvedeno v komentářích, SYSENTER
na mnoha 64bitových systémech Linux ve skutečnosti nefunguje — konkrétně 64bitové AMD systémy.
Je to jistě matoucí situace. Jsou zde krvavé detaily, ale jde o toto:
Pro 32bitové jádro jsou SYSENTER/SYSEXIT jediným kompatibilním párem [mezi procesory AMD a Intel]
Pro 64bitové jádro pouze v dlouhém režimu… SYSCALL/SYSRET jsou jediným kompatibilním párem [mezi procesory AMD a Intel]
Zdá se, že na Intel CPU v 64bitovém režimu, můžete se zbavit použití SYSENTER
protože dělá to samé jako SYSCALL
, to však není případ systémů AMD.
Sečteno a podtrženo:vždy používejte SYSCALL
v systému Linux na 64bitových systémech x86 . To je to, co x86-64 ABI ve skutečnosti specifikuje. (Další podrobnosti naleznete v této skvělé odpovědi na wiki.)