YouTube: System calls at the assembly level by Artem Pianykh
Linux .S
: AT&T Style Assembly
Interrupt handling has a lot of overhead.
as -32 interrupt.S -o interrupt.o;
ld --static -melf_i386 interrupt.o -o interrupt;
./interrupt
echo $? # 42
/*
* Arguments:
* eax system call number
* ebx arg1
* ecx arg2
* edx arg3
* esi arg4
* edi arg5
* ebp user stack
* 0(%ebp) arg6
*/
1 i386 exit sys_exit
as register.S -o register.o;
ld --static register.o -o register;
./register
echo $? # 42
6.1.1 SYSCALL and SYSRET
SYSCALL and SYSRET Instructions. SYSCALL and SYSRET are low-latency system call and return instructions. These instructions assume the operating system implements a flat-memory model, which greatly simplifies calls to and returns from the operating system. This simplification comes from eliminating unneeded checks, and by loading pre-determined values into the CS and SS segment registers (both visible and hidden portions). As a result, SYSCALL and SYSRET can take fewer than one-fourth the number of internal clock cycles to complete than the legacy CALL and RET instructions. SYSCALL and SYSRET are particularly well-suited for use in 64-bit mode, which requires implementation of a paged, flat-memory model.
60 common exit sys_exit
/*
* Registers on entry:
* rax system call number
* rcx return address
* r11 saved rflags (note: r11 is callee-clobbered register in C ABI)
* rdi arg0
* rsi arg1
* rdx arg2
* r10 arg3 (needs to be moved to rcx to conform to C ABI)
* r8 arg4
* r9 arg5
* (note: r12-r15, rbp, rbx are callee-preserved in C ABI)
*/
_start:
mov $1, %rax
mov $1, %rdi
mov hello_msg, %rsi
mov hello_msg_len, %rdx
syscall
jmp exit
exit:
mov $60, %rax # system call number: sys_exit(60)
mov $42, %rdi # return code
syscall
hello_msg:
.string "Hello, World!\n"
hello_msg_len = . - hello_msg
as hello.S -o hello.o;
ld --static hello.o -o hello;
./hello
[1] 57445 segmentation fault (core dumped) ./hello
man 2 write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
1 common write sys_write
/*
* Registers on entry:
* rax system call number
* rcx return address
* r11 saved rflags (note: r11 is callee-clobbered register in C ABI)
* rdi arg0
* rsi arg1
* rdx arg2
* r10 arg3 (needs to be moved to rcx to conform to C ABI)
* r8 arg4
* r9 arg5
* (note: r12-r15, rbp, rbx are callee-preserved in C ABI)
*/
gdb hello
(gdb) b _start
Breakpoint 1 at 0x401000
(gdb) layout asm
(gdb) r # run
(gdb) s # step
(gdb) q # quit
mov 0xf,%rdx
- wrong: memory address
0xf
→%rdx
- should be:
$0xf
_start:
mov $1, %rax
mov $1, %rdi
mov $hello_msg, %rsi
mov $hello_msg_len, %rdx
syscall
jmp exit
as hello.S -o hello.o;
ld --static hello.o -o hello;
./hello
Hello, World!
echo $?
42
cc hello.c -o helloc
./helloc
Hello, World!
echo $?
42
man 2 syscall
#include <unistd.h>
#include <sys/syscall.h> /* For SYS_xxx definitions */
long syscall(long number, ...);
man 3 strlen
#include <string.h>
size_t s trlen(const char *s);