自學組合語言的必備良方!

話說其實從大學起就一直都很想學組合語言,但一直都沒能夠成功的進入組語的學習領域。

後來陸陸續續接觸了一些其他的程式語言,玩到 Functional Programming 之後,也漸漸地把學組合語言這件事給拋到腦後了,畢竟光是玩 Functional Programming 就已經玩不玩了說。

只是後來又不小心進到了需要慣 C 的工作領域,重新在 Linux Kerenel 下面打轉,於是學組語這個念頭又回來了--畢竟,這是可是基礎中的基礎啊,而且追 Kernel 常常追到最後都是組語。

但問題是組語要怎麼學呢?我想一定也有很多想學組語,但和我一樣不得其門而入的朋友有相同的困擾。

以我自己而言,我有莫名其妙、不知道為何會出現的,從 80386 時代遺留下來的組語書籍(還用 PE2 咧),有自己去書局買的 NASM 的書,也有資工系開的組合語言課程的課本,甚至是網路上開放下載的教學書籍。

可是以上沒有任何一本書真正讓我進入組語的世界,理由很簡單--這些書我怎麼看都覺得不對勁,不知道該如何寫出我的第一隻組語程式。

有的一開始就和你講什麼 MOVL 是幹嘛用的,ADD 又是啥,但卻又沒有一隻完整的程式可以執行試驗--這樣根本就沒感覺啊!根本就不能從錯誤之中學習啊(例如隨便亂加兩個暫存器會怎樣)!

有的嘛,遵照古老的傳統,一開始就寫一個 Hello World 給你,然後再告訴你不要管那些 include 的黑魔法,反正程式可以跑就好--等一下,我學組語就是為了要了解最底層的運作,結果你叫我不要管他?

總而言之,看這些書的挫敗感真的很大,也因為如此,我一直沒有真正下定決心好好把組合語言給學起來。

一直到前一陣子,我在 Hacking Thursday 的討論區上看到這一本超級棒的書籍--Programming from the Ground Up,這真的是自學組合語言的好物啊!

廢話不多說,我們來看書中第一個程式範例:

.section .data
.section .text
.global  _start

_start:
    movl $1, %eax   # This is the linux kernel system call for exit
    movl $0, %ebx   # This is the status number return to OS
    int  $0x80      # This wake up the kernel to run system call

三行程式,而且每一行書裡面都解釋的很清楚(是的,包括 System Call 的部份也有說明,雖然經過簡化與譬喻),沒有任何的黑魔法。

同時,你也可以亂改這個程式,例如試著改變 EBX 暫存器的值,讓他返回不同的值給 Shell,又或者亂改 EAX 裡面的值,然後讓他產生 Segmentation Falut 而當掉。

真是太神奇有趣了!這才叫學組語嘛。

我真的很佩服作者可以想出把程式的結束狀態代碼當成輸出這個點子,完全避開了其他書裡面為了要產生輸出而不得不先使用黑魔法的問題。

再舉另一個例子,他的第二隻程式是介紹控制流程和迴圈,要透過他介紹的各種跳躍指令找到一個數列裡的最大值,這隻程式如下:

.section .data

items:
    .long 3, 6, 7, 10, 22, 34, 12, 0

.section .text
.global  _start

_start:
    movl $0, %edi             # move 0 to index register
    movl items(,%edi,4), %eax # load the first number
    movl %eax, %ebx           # put it to the EBX (cureent biggest)

start_loop:
    cmpl $0, %eax             # check to see if we've hit the end
    je   loop_exit

    incl %edi                 # increment index by 1
    movl items(,%edi,4), %eax # load next number
    cmpl %ebx, %eax           # compare with current biggest
    jle  start_loop           # jump to start_loop if not bigger
    movl %eax, %ebx           # else move this value as the largest
    jmp  start_loop           # next turn

loop_exit:
    movl $1, %eax             # System Call exit (No. 1)
    int  $0x80                # Singal batman

同樣的,這隻程式也是利用離開狀態做輸出--所以你用到的,都是你學過的東西,沒有黑魔法,每一行每一行都可以解釋到底是在做什麼,讓你驗證你是不是真的了解他。

另外,他用的是 GNU as 的語法,這對我而言有以下幾個好處:

  • 這是 Linux Kernel 裡面用的東西,我不用再去熟悉其他語法
  • 我只要有一台 Linux Box 就可以試著跑書裡的程式
  • 這意謂著你可以用 GCC 把 C 語言編譯到組合語言,然後和這本書裡面的範例做比對,例如講到 Function 的時候,你就可以寫幾個 C 語言函數來驗證書裡講的東西。

所以我一定要大推這一本書的啊~~這本書真的是自學組語的必備良方,只要會一點程式設計,一定可以看得懂的好東西!

回響