Linux provides a set of system calls aviable for each process. Some of the most used are:
Number | Name | Description |
0 | read | Read file |
1 | write | Write file |
2 | open | Open file |
3 | close | Close file |
4 | stat | Get info about file |
9 | mmap | Map memory page to file |
12 | brk | Reset top of the heap |
32 | dup2 | Copy file descriptor |
33 | pause | Suspend process until signal arrives |
37 | alarm | Schedule delivery of alarm signal |
39 | getpid | Get process id |
57 | fork | Create process |
59 | execve | Execute program |
60 | _exit | Terminate process |
61 | wait4 | Wait for a process to terminate |
62 | kill | Send signal to a process |
Now using the write we can perform a syscall asm-wise:
#include <stdio.h> __asm( //setup string named msg ".section .data;" "msg: .ascii \"Hello from global space!\n\";" "msg_end: .equ len, msg_end - msg;" ".section .text;" ); int main(){ __asm( //call write "movq $1,%rax;" "movq $1,%rdi;" "movq $msg,%rsi;" "movq $len,%rdx;" "syscall;" //call exit "movq $60,%rax;" "movq $0,%rdi;" "syscall;" ); }So we have chosen the syscall write with number 1, that number goes to rax. The next thing is to man 2 write which yields:
WRITE(2) Linux Programmer's Manual NAME write - write to a file descriptor SYNOPSIS #include <unistd.h> ssize_t write(int fd, const void *buf, size_t count);So we need arg fd - that is a file descriptor. STDIO has fd = 1. We need a buffer. That we have set up in the first __asm. Last we need a number of bytes to be written. This also has been set up in the first call to __asm. The last part of the code is a similar call to exit - let's man:
_EXIT(2) Programmer's Manual NAME _exit, _Exit - terminate the calling process SYNOPSIS #include <unistd.h> void _exit(int status); #include <stdlib.h> void _Exit(int status);As before we man for the type signature. In this case we need rax to be 60, as that it the number of the syscall, and we need to pass the exit status as 0. Pretty low level!