pretty code

顯示具有 Assembly 標籤的文章。 顯示所有文章
顯示具有 Assembly 標籤的文章。 顯示所有文章

2021年12月22日 星期三

x86 assembly in Linux - part 7

"Programming from the Ground Up" 第三章有一節 "Addressing Modes" (P.41),會描述各種定址方式的寫法,久沒寫組語,想要重頭溫習一定要來看這一節。

另外,就是 stack (第四章) 的傳遞,久沒碰真的會忘記,當然 x64 函數參數還會用到暫存器 (以 Windows 來說是前 4 個參數),剩下的才用 stack。

總之,記錄一下避免下次還要重頭回想。

2019年7月2日 星期二

人體 Compiler 果然很難

今天在測試 struct memory dump 時,無意間發現使用 gcc -S 轉出來的組語很不一樣,我只能說再給我 10 年我也不會想到可以這樣寫,組語其實也蠻有趣的XD


2018年12月14日 星期五

UEFI Application - Stack overflow

最近在幫同事看一個問題
覺得很有趣,故記錄一下解題思路

同事在 build code 時,發現一個 link error
正在產生程式碼
已完成程式碼產生
UefiApplicationEntryPoint.lib(ApplicationEntryPoint.obj) : 
error LNK2001: 無法解析的外部符號 __chkstk

網路查了一下,是因為 VC compiler 檢查到某些 function  有 stack 問題時
便會在 code 中插入 __chkstk 這個 check function

網路看到的解法都是放大 stack size
可以在 INF 檔案編譯選項中加入 /GsXXXXX
但據實測的結果是一點用處都沒有
stack size 還是維持在 32K 左右

後來試著在 INF 檔案編譯選項中加入 /FAcs 選項
此選項會產生 assembly 檔案
副檔名為 .cod

接著在 UDK\Build\程式路徑中
用 grep 搜尋 __chkstk 關鍵字
便可以看到是那個 function 被插入了 __chkstk

底下是我模擬的結果
很明顯的看到 rsp register 被保留了 32776 這麼大的空間(char LocalVar[32768])
當然會造成 stack overflow



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

2017年11月7日 星期二

x86 Assembly Intel to AT&T

最近工作需要使用人家寫好的組語去控制 HW
我需要的是 AT&T 語法
不過因為對方不熟 AT&T 語法
故需轉換對方寫的 Intel 語法

本想直接人工轉換,但又怕不懂組語的我做白工
上網搜尋了一下,找到一個專案 ta2as
試了一下,只要調整來源檔輸出,就能順利的轉出 AT&T 語法
除了 mox 指令 找不到改用 movb 以外(有誰可以告訴我有 mox 指令 嗎?)
使用起來感覺沒什麼問題

另外,有參考 purpose 網友的 PTT 文章 ,好確認 ta2as 工具是否有轉錯

題外話,很久以前就想學組語,不過一直抽不出時間
brianhsu 網友有另外一篇 PTT 文章,推薦學組語的參考書籍
記錄一下當作備忘