I would like to know what are the different ways to perform a system
call in x86 assembler under Linux. But, with no cheating, only
assembler must be used (i.e. compilation with gcc
must be done with
-nostdlib
).
I know four ways to perform a system calls, namely:
int $0x80
sysenter
(i586)call *%gs:0x10
(vdso trampoline)syscall
(amd64)
I am pretty good at using int $0x80
, for example, here is a sample
code of a classic 'Hello World!' in assembler using int $0x80
(compile it with gcc -nostdlib -o hello-int80 hello-int80.s
):
.data
msg:
.ascii "Hello World!\n"
len = . - msg
.text
.globl _start
_start:
# Write the string to stdout
movl $len, %edx
movl $msg, %ecx
movl $1, %ebx
movl $4, %eax
int $0x80
# and exit
movl $0, %ebx
movl $1, %eax
int $0x80
But the sysenter
is often ending with a segmentation fault error. Why ? And, how to use it right ?
Here is an example with call *%gs:0x10
(compiled with gcc -o hello-gs10 hello-gs10.s
). Note that I need to go through the libc
initialization before calling it properly (that is why I am using main
and not anymore _start
and, that is also why I removed the option -nostdlib
from the compile line):
.data
msg:
.ascii "Hello World!\n"
len = . - msg
.text
.globl main
main:
# Write the string to stdout
movl $len, %edx
movl $msg, %ecx
movl $1, %ebx
movl $4, %eax
call *%gs:0x10
# and exit
movl $0, %ebx
movl $1, %eax
call *%gs:0x10
Also, the syscall
is working pretty well also if you know the syscall codes for this architecture (thanks to lfxgroove) (compiled with: gcc -m64 -nostdlib -o hello-syscall hello-syscall.s
):
.data
msg:
.ascii "Hello World!\n"
len = . - msg
.text
.globl _start
_start:
# Write the string to stdout
movq $len, %rdx
movq $msg, %rsi
movq $1, %rdi
movq $1, %rax
syscall
# and exit
movq $0, %rdi
movq $60, %rax
syscall
So, the only problem I have to trigger a system call is this sysenter
way. Here is an example with sysenter
ending with a segmentation fault (compiled with gcc -m32 -nostdlib -o hello-sysenter hello-sysenter.s
):
.data
msg:
.ascii "Hello World!\n"
len = . - msg
.text
.globl _start
_start:
# Write the string to stdout
movl $len, %edx
movl $msg, %ecx
movl $1, %ebx
movl $4, %eax
push final
sub $12, %esp
mov %esp, %ebp
sysenter
# and exit
final:
movl $0, %ebx
movl $1, %eax
sub $12, %esp
mov %esp, %ebp
sysenter
syscall
that was calling thewrite
(and not the first one, as I was expecting).len = . - msg
- edit : I know of the purpose by obvious reasons but the semantics of it. - Thanks.
' in the gas syntax refer to the current address. So,len = . - msg
is a way to store inlen
the size of the stringmsg
(it computes the difference between the current address and the position of themsg
label).