有天,突然臨時起意想要學習組合語言,所以呢首先來熟悉一下一些基本的東西。本程式唯一的功能,是利用sys_exit,一個system call,來結束程式,並把exit code設定為0。(OS:好心酸)。程式碼如下:
.text .global _start .type _start, @function /* _start是真正的程式進入點 在C語言中,編譯器會幫你產生一個可以導向到main的_start函數 */ _start: /* 注意: 要把常數輸送到暫存器,使用 mov $60, %rax 使用下面的指令會把記憶體位置 60 (0x3C)的資料傳送到rax中。 mov 60, %rax sys_exit, syscall number為60 (依據asm/unistd_64.h) 第一個參數為exit code */ mov $60, %rax /*syscall number傳送到 rax*/ mov $0, %rdi /*第一號參數傳送到 rdi*/ syscall /*調用sys_exit。程式在此領便當。*/ /* 不能用ret來結束。 _start是「創世函數」,而ret是用來把控制權轉交給呼叫此函數的函數 所以ret會導致不可預期的結果發生 C語言的main可以用return(被翻譯成ret),是因為main可以回到_start */
想要編譯它的話請使用下面的指令:
gcc -nostartfiles exit.s
這份程式碼使用的x86-64語法是AT&T的語法(AT&T syntax)和Intel官方的語法有很大的不同。其中最重要也是最主要的差異是在運算為的排放。舉例來說,Intel syntax下,把60放到rax暫存器為:
mov rax, 60
但在AT&T syntax下則是:
mov $60, %rax
大部分的x86-64程式設計人員使用的是Intel syntax。但私心覺得AT&T syntax看起來很順眼,而且GNU assembler使用這樣的語法,所以就決定學這一套了。
回到本程式的另一個重點,system call的使用。System call是直接和Linux kernel溝通的方法,可以調用kernel所提供的一些基本功能。依據x86-64 ABI(詳細見這裡),要進行system call,首先要在rax暫存器上面填入system call number,接著,在依照rdi, rsi, rdx, r10, r8, r9的順序把參數填入。在這個程式裡面,因為sys_exit的參數只有一個,所以把它填入rdi中。完成上面的佈置後,利用syscall指令來進行system call。
沒有留言:
張貼留言