【linux】masm匯編系統調用說明


寫在前面的話

高級語言有Java golang C等,通過系統調用訪問系統的資源,那底層的匯編代碼是如何運行的,此文通過匯編語言簡單的說明系統調用。

 

環境准備安裝nasm

osx系統通過brew安裝

brew install nasm

CentOS7環境下源碼安裝

下載匯編編譯器nasm:https://www.nasm.us/

wget https://www.nasm.us/pub/nasm/releasebuilds/2.15.05/nasm-2.15.05.tar.gz
tar -xvf nasm-2.15.05.tar.gz && cd nasm-2.15.05.tar.gz && ./configure && make && make install

Unbuntu環境下安裝

sudo apt-get install nasm

 

匯編說明

一個匯編的簡單例子 hello.asm

section .data
msg: db "hello world", 0x0a
len: equ $-msg
    SYS_WRITE equ 1
    STD_OUT equ 1
    SYS_EXIT equ 60

section .text
    global _start
_start:
    mov rax, SYS_WRITE
    mov rdi,STD_OUT
    mov rsi,msg
    mov rdx,len
    syscall
    jmp exit

exit:
    mov rax,SYS_EXIT
    mov rdi,0
    syscall

 

編譯如下匯編文件

hello:
    nasm -f elf64 -o hello.o hello.asm
    ld -o hello -e _start hello.o

clean:
    rm hello hello.o

nasm支持的輸出文件格式包括 linux的elf64 elf32以及macox的macho32 mach64等

 

使用C代碼解析

#include <stdio.h>

const char *msg= "hello world\n";
const int len = 12;
int main() {
    write(1, msg, len);
    exit(0);
    return 0;
}

 

將如下C代碼編譯成匯編

gcc -S hello.c產生hello.s匯編文件內容如下

    .file    "hello.c"
    .globl    msg
    .section    .rodata
.LC0:
    .string    "hello world\n"
    .data
    .align 8
    .type    msg, @object
    .size    msg, 8
msg:
    .quad    .LC0
    .globl    len
    .section    .rodata
    .align 4
    .type    len, @object
    .size    len, 4
len:
    .long    12
    .text
    .globl    main
    .type    main, @function
main:
.LFB0:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $12, %edx
    movq    msg(%rip), %rax
    movq    %rax, %rsi
    movl    $1, %edi
    movl    $0, %eax
    call    write
    movl    $0, %edi
    call    exit
    .cfi_endproc

對比如上兩個匯編,基本一致。

 

數據段 .data

數據段用於定義常量,在運行時不可改變,定義語法如下

section .data
msg: db "hello world", 0x0a
len: equ $-msg

解析:

定義數據段: section .data 

 

聲明一個字符串,以換行結尾:msg: db "hello world", 0x0a

對應的C代碼的

const char *msg= "hello world\n";

db的含義是定義字節 byte,每個字符是一個字節。

另外還有兩個字節的dw,以及其他的

dx := DB | DW | DD | DQ | DT | DO | DY | DZ

type := BYTE | WORD | DWORD | QWORD | TWORD | OWORD | YWORD | ZWORD

聲明一個長度常量,取值字符串的長度:len: equ $-msg

equ的含義是定義一個常量的符號,取值是一個常量。

對應的C代碼

const int len = 12;

 

代碼段 .text

代碼段用於代碼,代碼段需要以global _start開頭,告訴系統這是代碼的入口,定義語法如下:

section .text
    global _start
_start:

解析:

定義代碼段:section .text

定義代碼的全局入口標簽:global _start

代碼標簽開始:_start:

 

從CPU運行的角度分析代碼段

CPU簡潔執行步驟是 加載指令,解碼指令,運行指令

 

 

 CPU在時鍾驅動下,從內存加載,解碼和運行指令順序如下所示:

 

控制台標准輸出字符串的匯編解析

mov rax,1
mov rdi,1
mov rsi,msg
mov rdx,len
syscall

對應C代碼

write(1, hello, 12);

解析:

mov rax,1 表示將__NR_write的系統調用號賦值給寄存器RAX,對應write系統調用函數,#define __NR_write 1
mov rdi,1 表示給系統調用write傳遞第一個參數,參數值等於1,表示控制台標准輸出stdout
mov rsi, msg 表示給系統調用write傳遞第二個參數,參數值等於msg字符串指針,即"hello world\n"
mov rdx, len 表示給系統調用write傳遞第三個參數,參數值等於msg字符串的長度,即12
syscall 表示執行系統調用write

本文使用osx和Centos7系統實驗。

 

退出程序的匯編

    mov rax,60
    mov rdi,0
    syscall

對應C代碼

exit(0);

解析:

mov rax,60 表示將__NR_exit的系統調用號賦值給寄存器RAX,對應exit系統調用函數,#define __NR_exit 60
mov rdi,0 表示給系統調用exit傳遞第一個參數,參數值等於0
syscall 表示執行系統調用exit

在linux系統上可以查看/usr/include/asm/unistd_64.h獲取常用的系統調用函數的系統調用號

#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3

// ...
#define __NR_exit 60
// ...
#define __NR_pkey_free 331

 

如上就將簡單的helloworld的匯編解析完畢,那么為什么要使用到rax rdi rsi rdx這些寄存器呢,

原因是CPU規定64位系統函數調用的參數傳遞使用的寄存器如下

RDI 傳遞第一個參數
RSI 傳遞第二個參數
RDX 傳遞第三個參數
RCX 傳遞第四個參數
R8 傳遞第五個參數
R9 傳遞第六個參數

 

對應的macos的代碼如下,區別是不同系統的系統調用號不同

hello.asm

section .data
msg: db "hello world", 0x0a
len: equ $-msg
    SYS_WRITE equ 0x2000004
    STD_OUT equ 1
    SYS_EXIT equ 0x2000001

section .text
    global _start
_start:
    mov rax, SYS_WRITE
    mov rdi,STD_OUT
    mov rsi,msg
    mov rdx,len
    syscall
    jmp exit

exit:
    mov rax,SYS_EXIT
    mov rdi,0
    syscall

 

編譯的Makefile

hello:
    nasm -f macho64 -o hello.o hello.asm
    ld -o hello -e _start hello.o -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lSystem

clean:
    rm hello hello.o

在macos系統上生成二進制文件需要鏈接 -lSystem庫才可以執行。

 

更多的匯編代碼可以學習nasm的匯編文檔說明:

https://www.nasm.us/pub/nasm/releasebuilds/2.15.05 

參考材料:

https://0xax.blogspot.com/2014/08/say-hello-to-x64-assembly-part-1.html

https://github.com/0xAX/asm

 

祝玩的開心~

done.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM