使用環境:
- Linux 2.6.24.1
- yasm 0.7.1.2093
- GNU ld 2.15.92.0.2 20040927
在 Linux 下,要使用 system call,可以透過 int 0x80 來完成。
首先,要先找出 system call 對應的號碼,後面會用到;號碼可以在 sys/syscall.h 中找到。如果看到 syscall.h 裡只有 include 其他 header file,請繼續追著這些 header file 往下找。例如,在我使用的機器上,sys/syscall.h include 了 asm/unistd.h,asm/unistd.h 又呼叫了 asm/unistd_32.h,最後在 asm/unistd_32.h 內找到了如下列的號碼
#define __NR_restart_syscall 0
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
..... (以下還有好多,省略)
如果你要使用 read() 的 system call,號碼就是 3 號,要用 open(),號碼就是 5 號,其他以此類推。
知道了號碼之後,正式進入如何透過 int 80 來使用 system call 的主題。
先來個 C 的簡單範例。
#include <unistd.h>
int main(int argc, char *argv[])
{
char str[] = "Hello World!\n";
write(1, str, sizeof(str));
return 0;
}
上例中,我們使用了 write,將 str 字串寫到 standard output (就是 write() 的那個 1) ,也就是螢幕上。這個程式可以將字串內的內容顯示在螢幕上。
接著,一模一樣的事,我們使用 assembly code 來實現。
section .text
global _start
_start:
mov edx,len ;message length
mov ecx,msg ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db 'Hello, world!',0xa,0xd,0 ;our string
len equ $ - msg ;length of our dear string
在使用 int 0x80 之前,必須要將我們剛查出來的號碼填到 eax 內;填好後,只要一使用 int 0x80,相對應的 system call 就會被呼叫。
另外,system call 的參數要依序被放在 ebx, ecx, edx, esi, edi, ebp 等 register 內;以此例來說,一開始,我們使用 sys_write,查表得到號碼是 4 號,於是將此號碼填入 eax;接著,我們要將三個參數搬到對應的 register 內;參考 C 程式,write 有三個參數,分別是 1, string buffer 的位址,及 string buffer 的長度;這三個參數在呼叫 0x80 之後,也必須分別擺到 ebx, ecx, edx 內。全部擺好後,最後使用 int 0x80,噹啷~ Hello, World! 就顯示在螢幕上了。
最後,程式要離開,我們使用了 sys_exit,也就是 1 號的 system call,離開程式。
Reference: http://asm.sourceforge.net//intro/hello.html#AEN86