The first observation is that the code in both your examples effectively do the same thing, but are encoded differently. The site x86-64.org has some good information for those starting out with x86-64 development. The first code snippet that uses 32-bit registers is equivalent to the second because of Implicit Zero Extend:
Implicit zero extend
Results of 32-bit operations are implicitly zero extended to 64-bit values. This differs from 16 and 8 bit operations, that don't affect the upper part of registers. This can be used for code size optimisations in some cases, such as:
movl $1, %eax
xorq %rax, %rax
andl $5, %eax
The question is, why does this code segfault? If you had run this code on a typical x86-64 Linux distro your code may have exited as expected without generating a segfault
. The reason that your code is failing is because you are using a custom kernel with IA32 emulation off.
IA32 emulation in the Linux kernel does allow you to use the 32-bit int 0x80
interrupt to make calls using the traditional 32-bit system call mechanism. This is an emulation layer, and doesn't support passing pointers that can't be represented in a 32-bit register. This is the case for stack based pointers since they fall outside the 4gb address space, and can't be accessed with 32-bit pointers.
Your system has IA32 emulation off, and because of that int 0x80
doesn't exist for backwards compatibility. The result is that the int 0x80
interrupt will throw a segmentation fault and your application will fail.
In x86-64 code it is preferred that you use the syscall
instruction to make system calls to the 64-bit Linux kernel. This mechanism supports 64-bit operands and pointers where necessary. Ryan Chapman's site has some good information on the 64-bit SYSCALL interface which differs considerably from the 32-bit int 0x80
mechanism.
Your code could have been written this way to work in a 64-bit environment without IA32 emulation:
.section .text
.globl _start
_start:
mov $60, %eax
xor %ebx, %ebx
syscall
Other useful information on doing 64-bit development can be found in the 64-bit System V ABI. This document also better describes the general syscall
convention used by the Linux kernel including side effects in Section A.2 . This document is also very informative if you also wish to interface with third party libraries and modules (like the C library etc).
int 0x80
still exist in x86_64 ? I thought it has been replaced withsyscall
instruction – Pierreint 0x80
withsyscall
gives meSegmentation fault
, too. – Cágint 0x80
in 64-bit code. You'll need to use the 64-bitsyscall
instruction and convention. A good starting point for that is blog.rchapman.org/post/36801038863/… .If you turn on IA32 emulation your kernel can useint 0x80
in 64-bit code, but is limited to 32 bit operands and 32-bit pointers. The upper 32-bits aren't used with IA32 emulation. One downside is stack based pointers can't be passed toint 0x80
– Michael Petchsyscall
instruction is preferred. The calling convention and numbering is different thanint 0x80
– Michael Petch