2018年9月27日 星期四

x86 Assembly in Linux - part 6

寫組語前除了用紙筆安排要用的暫存器外,最好也是分段撰寫,這樣比較方便除錯。

大部份的錯誤都是常數忘記加上 "$",或是 instruction 的單位用錯

即使如此,code 還是常常不如預期,幸好我們可以很簡單的用 GDB 來 debug。

相關步驟如下:
"as -gstabs add debug information to object
"objdump -D a.out | less" or "nm a.out" 利用此步驟找到相關變數或 label 的 address
"gdb a.out" 執行 GDB
"b label name" 對要監控的 label 下斷點
"display /i $pc" 顯示當前執行的組語
"run" 執行程式
斷點觸發
"info all-registers" 觀看目前所有暫存器值
"p $eax" 觀看 eax
"p abc" 觀看 variable abc
"x/x address" 觀看 address hex value
"step" 單步執行

當然也可以使用包裝 GDB 的 GUI tool。

x86 Assembly in Linux - part 5

因為趕專案沒什麼時間,諷刺的是我也是因為專案才開始學組語
當初設想的目標就是可以用組語寫出猜數字的小遊戲

扣掉重覆的 function 行數約 361 行
如果用 Go 或是 C 大概只需要不到 100 行

雖然寫出了猜數字組語版
但 "Programming from the Ground Up" 還是停留在第 5 章沒有進度
之後大概也沒有時間再看了

安西教練,我好想打籃球 !!!

https://github.com/tylpk1216/1A2B/blob/master/guessnum.s

2018年9月20日 星期四

x86 assembly in Linux - part 4

在高階語言的世界裡 printf 就像喝水一樣
往往是最常用的 debug 工具之一

但在組語的世界裡
在還不會呼叫 C 語言函式庫前
你是無法跟螢幕打交道的

幸好我們還是可以透過 system call 來做這件事
用的是 write system call
差別在 file descriptor 是 STDOUT ($1)

底下是個包裝好的函式
接收 1 個參數,指向 C語言字串 (null-terminated string) 的 address 位址
參數傳遞方式是使用 stack

.type myprint,@function
myprint:
    pushl %ebp
    movl %esp, %ebp

    # get msg address
    movl 8(%ebp), %ecx

    # get msg length
    movl $0, %edx

start_loop:
    cmpb $0, (%ecx)
    je end_loop

    incl %ecx
    incl %edx

    jmp start_loop

end_loop:
    movl $4, %eax
    movl $1, %ebx
    movl 8(%ebp), %ecx
    int $0x80

    movl %ebp, %esp
    popl %ebp
    ret

x86 assembly in Linux - part 3

雖然 "Programming from the Ground Up" 還沒看完
在知道了如何呼叫 linux system call 後 (exit)
便想找 1 個簡單的 system call 來試試

看來看去 mkdir 算是相對簡單的
不過卻讓我卡了 2 天

直到今天才恍然大悟自己錯在哪裡
原來我只顧著 create directory
卻沒有 call exit system call
難怪死得不明不白

.section .data
name:
    .string "MK"

.section .text

.global _start

_start:
    movl $39, %eax
    movl $name, %ebx
    movl $0777, %ecx
    int $0x80

    movl $1, %eax
    movl $0, %ebx
    int $0x80

x86 assembly in Linux - part 2

"Programming from the Ground Up" 的作者建議寫組語時
最好是拿紙筆把要用到的暫存器安排一下
寫起 code 來會比較順暢

昨天回家洗澡時就想到
part 1 的 example 做了一些很不必要的動作
也多用到一些不必要的暫存器

舉例來說
%ebx 存起的是 memory address
也是我存放要比較整數的 list (array)

原本 for loop 都會用 %edi 來當 index variable
但在這個 case 其實是不必要的
因為我們本來就可以對暫存器直接做加減

start_loop:
    incl %edi

    movl $4, %edx
    imull %edi, %edx
    addl %ebx, %edx

start_loop:
    addl $4, %ebx

2018年9月19日 星期三

x86 assembly in Linux - part 1

目前看的書是網路很推薦的 "Programming from the Ground Up"
由於這本書介紹的是 32 位元的組語寫法
故在編譯成 64 位元的 code 時會有問題

此時需指定 --32 to as and -m elf_i386 to ld

as source.s --32 -o source.o
ld source.o -m elf_i386 -o source.out

另外,如果在 call function 時,想把 label's address pass to function
在 label 前面,需加上 "$"

底下是個 example,max function 會幫忙把資料組裡的最大值找出
並將回傳值放進 %eax register

.section .data
list:
    .long 31,2,199,7,0

.section .text

.global _start

_start:

    pushl $list
    call max
    addl $4, %esp

    movl %eax, %ebx
    movl $1, %eax
    int $0x80

.type max,@function
max:
    pushl %ebp
    movl %esp, %ebp

    movl 8(%ebp), %ebx

    movl $0, %edi

    movl $4, %edx
    imull %edi, %edx
    addl %ebx, %edx
    movl (%edx), %eax

start_loop:
    incl %edi

    movl $4, %edx
    imull %edi, %edx
    addl %ebx, %edx
    movl (%edx), %ecx

    cmpl $0, %ecx
    je end_loop

    cmpl %eax, %ecx
    jle start_loop

    movl %ecx, %eax
    jmp start_loop

end_loop:
    movl %ebp, %esp
    popl %ebp
    ret

2018年9月13日 星期四

big-endian and little endian

雖然知道這個的不同
但每次都會忘記記憶體位置的順序
乾脆畫了一個圖來幫助記憶

大概只有 3 個重點
1. 計憶體位置是由低到高
2. 最高位元的資料 (0x12) 先擺就是 big-endian
3. 相反就是 little-endian