本文目標:在 Linux 平臺中,利用 nasm 與 gdb 快速構建一個編譯與除錯工具鏈,以下僅做簡單演示。
主要還是因為學習“計算機組成原理”中 intel 指令相關內容的時候,太生澀難懂了。就是想簡單實操一下,深刻理解,因此才出了這篇文章。
我們以一下程式為例舉例說明。
section .data
hello db "hello, world", 10 ; 定義要輸出的字串,10 是換行符的 ASCII 碼
hello_len equ $ - hello ; 計算字串長度
section .text
global _start ; 必須宣告 _start 為全域性符號,這是連結器識別的入口點
; 呼叫系統呼叫 exit
exit:
mov rax, 1 ; 系統呼叫號,這裡是 exit
int 0x80 ; 觸發系統呼叫
; 一個簡易的加法函式
; 傳參暫存器 edi, esi
add:
push rbp
mov rbp, rsp
; 函式無變數
mov [rbp - 4], edi
mov [rbp - 8], esi
mov edx, [rbp - 4]
mov eax, [rbp - 8]
add eax, edx
pop rbp
ret
; 入口函式
_start:
; 呼叫系統呼叫 write 功能, 向終端輸出文字
mov eax, 4 ; 系統呼叫號,這裡是 write
mov ebx, 1 ; 檔案描述符 1,代表標準輸出
mov ecx, hello ; 字串的地址
mov edx, hello_len ; 字串長度
int 0x80 ; 觸發系統呼叫
mov edi, 10
mov esi, 20
call add
mov rbx, rax
jmp exit
如何使用 NASM 編譯生成可執行檔案
在 Linux 平臺上,我們可以直接使用 nasm 生成 elf 可執行檔案,目前 nasm 提供了兩種生成方法。
-
生成可重定向目的碼,然後再連結程式碼。
nasm -f elf64 test.asm -o test.o ld -o test test.o
-
直接生成可執行檔案。
nasm -f aout test.asm -o test
如何使用 GDB 除錯生成的程式碼
由於我們生成的程式碼並不可能包含除錯資訊,以至於我們在除錯的時候困難重重。我們只能使用 disassemble
指令來檢視除錯內容。
gdb ./test # 執行指令
# 以下是互動式介面需要執行的命令
break _start # 在 _start 處新增短點資訊
run # 執行程式
layout asm # TUI顯示彙編資訊
layout regs # TUI顯示暫存器資訊
以下是一些常用命令:
info registers
:檢視所有暫存器資訊stepi
:單次執行一條指令continue
:繼續執行指令break *0x401016
:在指定記憶體位置新增端點x /10x $sp - 16
:檢視 esp - 16 所在記憶體的連續 10 個 dword 大小的記憶體空間資料。
除錯的時候需要注意位數(64 位佔 8 位元組),以及intel處理器為小端方式。