我的匯編學習之路(1):指令
來源:易賢網(wǎng) 閱讀:1184 次 日期:2015-04-02 14:09:40
溫馨提示:易賢網(wǎng)小編為您整理了“我的匯編學習之路(1):指令”,方便廣大網(wǎng)友查閱!

引言

我們很多人是開發(fā)者,每天寫大量的代碼,有時也不是糟糕的代碼。每個人都能很輕松寫下這樣的代碼:

#include <stdio.h>

int main() {

int x = 10;

int y = 100;

printf("x + y = %d", x + y);

return 0;

}

大家都能理解上面這段 C 語言代碼完成的功能,但是…這段代碼底層是如何工作的呢?我想我們中間不是所有人都能回答這個問題,我也不能。我認為我可以用高級編程語言寫代碼,例如 Haskell、Erlang、Go 等等,但是我完全不知道在編譯之后它在底層是如何工作的。所以,我決定往下再深入一步,到匯編這個層次,并且記錄下我的學習匯編之路。希望這是有趣的過程,而不是僅僅對我一個人。大約五、六年前我已經(jīng)使用過匯編來寫簡單的程序,那時我還在上大學,用的是 Turbo 匯編和 DOS 操作系統(tǒng)?,F(xiàn)在我使用 Linux-x86_64 操作系統(tǒng),是的,64 位 Linux 和 16 位 DOS 肯定有很大的不同。那我們就開始吧。

準備階段

在開始之前,我們需要準備一些我接下來要提到的東西。我使用的是 Ubuntu(Ubuntu 14.04.1 LTS 64 位) 系統(tǒng),因此我的文章都是基于該操作系統(tǒng)和體系結(jié)構(gòu)的。不同的 CPU 支持不同的指令集,我使用的是 Intel Core i7 870 處理器,所有代碼都在這上面運行。另外我將用 nasm 匯編,你可以用下面命令來安裝:

sudo apt-get install nasm

I它的版本應該是 2.0.0 或者更高了。我是用的是 2013年12月29日編譯的 NASM version 2.10.09 版本。最后一部分,你需要一款寫匯編代碼的文本編輯器,我使用配有 nasm-mode.el 的 Emacs 編輯器。當然這不是強制性的,你可以選擇任何你喜歡的文本編輯器。如果你像我一樣使用的是 Emacs,你可以下載 nasm-mode.el,將你的 Emacs 配置成這樣:

(load "~/.emacs.d/lisp/nasm.el")

(require 'nasm-mode)

(add-to-list 'auto-mode-alist '(".(asm|s)$" . nasm-mode))

這就是目前我們需要準備的所有東西,其它工作在接下來的文章中會提到。

x64 語法

這里我就不全面介紹匯編的語法了,我們僅提一下這篇文章中用到的語法。通常 NASM 程序會被劃分為不同的段(section),這篇文章中我們會涉及到兩個段:

數(shù)據(jù)段(data section)

代碼段(text section)

數(shù)據(jù)段用來定義常量(constant),常量是在運行時不會改變的數(shù)據(jù)。你可以定義數(shù)字或其他常量等等,聲明一個數(shù)據(jù)段的語法如下:

section .data

代碼段是存放代碼(code)的,該段必須以 global_start 開始,告訴內(nèi)核這里是程序開始執(zhí)行的地方。

section .text

global _start

_start:

注釋是以 ; 開始。每個 NASM 代碼行包含下面四個字段的組合:

[label:] instruction [operands] [; comment]

中括號括起來的字段表示是可選的?;?NASM 指令由兩部分組成,第一部分是需要執(zhí)行指令的名字,第二部分是該指令的操作數(shù)。例如:

MOV COUNT, 48 ;將數(shù)值 48 存放到 COUNT 變量中

Hello world

讓我們用 NASM 匯編來寫第一個程序吧,當然是傳統(tǒng)的打印 “Hello world” 的程序。這是代碼:

section .data

msg db "hello, world!"

section .text

global _start

_start:

mov rax, 1

mov rdi, 1

mov rsi, msg

mov rdx, 13

syscall

mov rax, 60

mov rdi, 0

syscall

的,看起來不像 printf(“Hello world”),我們試著去理解它是什么、怎么工作的。先看 1-2 行,我們定義了一個數(shù)據(jù)段,并且有一個 msg 常量,值為 Hello world,那么我們就可以在代碼中使用這個常量了。下一步是定義了一個代碼段,以及程序的入口,代碼從第 7 行開始執(zhí)行。現(xiàn)在到了程序最有意思的部分了。我們已經(jīng)了解了 mov 指令的功能,它帶有兩個操作數(shù),將第二個操作數(shù)的值放到第一個操作數(shù)中。但是,rax、rdi 等等這些是什么呢?我們找到維基百科的解釋:

中央處理單元(CPU)是計算機中的硬件,它讀取計算機程序中的指令,完成系統(tǒng)中基本的算術、邏輯、輸入/輸出操作。

好了,CPU 完成一些操作,例如算術操作等,但是它從哪獲得操作的數(shù)據(jù)呢?第一個答案是內(nèi)存。然而從內(nèi)存中讀取和存入數(shù)據(jù)的速度遠遠低于處理器的速度,它涉及到復雜的通過控制總線來發(fā)送數(shù)據(jù)請求的過程。因此,CPU 有其內(nèi)部的存儲位置,稱為寄存器(register)。

x64_registers

那么我們寫 mov rax, 1,意思是將 1 放到 rax 寄存器中?,F(xiàn)在我們知道什么是 rax、rdi、rbx 等等了吧,但是還需要知道什么時候使用 rax,什么時候使用 rsi 等等。

rax —— 臨時寄存器,當我們調(diào)用系統(tǒng)調(diào)用時,rax 保存系統(tǒng)調(diào)用號

rdx —— 用來向函數(shù)傳遞第三個參數(shù)

rdi —— 用來向函數(shù)傳遞第一個參數(shù)

rsi —— 用來向函數(shù)傳遞第二個參數(shù)的指針

換句話說,我們就是調(diào)用了 sys_write 系統(tǒng)調(diào)用,該函數(shù)原型是:

ssize_t sys_write(unsigned int fd, const char *buf, size_t count)

它有三個參數(shù):

fd —— 文件描述符,0、1、2 分別代表標準輸入、標準輸出和標準錯誤

buf —— 字符數(shù)組的指針,用來保存從 fd 指向的文件中獲取的內(nèi)容

count —— 表示要從文件中讀入到字符數(shù)組的字節(jié)數(shù)

我們知道 sys_write 系統(tǒng)調(diào)用帶有三個參數(shù),它在系統(tǒng)調(diào)用表中有一個系統(tǒng)調(diào)用號。我們再看看程序的實現(xiàn),將 1 放到 rax 寄存器中,它意思是我們使用 sys_write 系統(tǒng)調(diào)用;下一行將 1 存到 rdi 寄存器,它是 sys_write 的第一個參數(shù),1 代表標準輸出;然后我們將 msg 的指針存到 rsi 寄存器中,這是 sys_write 的第二個參數(shù) buf;接著我們傳遞 sys_write 最后一個參數(shù)(字符串的長度)到 rdx 寄存器中?,F(xiàn)在,我們有了 sys_write 的所有參數(shù),就可以在 11 行使用 syscall 來調(diào)用它了。好了,我們打印出 “Hello world” 字符串,現(xiàn)在需要從程序中正確退出。我們傳遞 60 到 rax 寄存器,60 是 exit 的系統(tǒng)調(diào)用號;以及將 0 傳遞給 rdi 寄存器,這是錯誤碼,0 表示我們的程序正確地退出。這就是 “Hello world” 的所有分析,相當簡單吧:)現(xiàn)在我們編譯程序,假設我們的程序放在 hello.asm 文件中,那么我們需要運行下面的命令來執(zhí)行:

nasm -f elf64 -o hello.o hello.asm

ld -o hello hello.o

編譯鏈接完成之后,我們得到可執(zhí)行文件 hello,可以使用 ./hello 來運行,可以在終端看到輸出 “Hello world”。

總結(jié)

本文用一個簡單不能再簡單的程序開始第一部分,接下來我們會看到一些算術運算。如果你有任何問題或者建議可以給我評論。

更多信息請查看IT技術專欄

更多信息請查看技術文章
易賢網(wǎng)手機網(wǎng)站地址:我的匯編學習之路(1):指令

2025國考·省考課程試聽報名

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 加入群交流 | 手機站點 | 投訴建議
工業(yè)和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網(wǎng)安備53010202001879號 人力資源服務許可證:(云)人服證字(2023)第0102001523號
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關注公眾號:hfpxwx
咨詢QQ:526150442(9:00—18:00)版權(quán)所有:易賢網(wǎng)