Linux 的 x86 彙編程式設計(轉)
Linux 的 x86 彙編程式設計(轉)[@more@]本質上來說, 這篇文章是把我最感興趣的兩樣程式設計東西: Linux 作業系統和組合語言程式設計結合在一起. 這兩個都不(或者說應該不)需要介紹; 像 Win32 的彙編,Linux 的彙編執行在 32 位的保護模式下...但它又有一個截然不同的優勢就是它允許你呼叫 C 的標準庫函式和 Linux 的共享庫函式. 我開始給 Linux 下的組合語言程式設計來個簡要介紹; 為了更好讀一點, 你可能要跳過這個基本的小節.
編譯和連結
---------------------
Linux 下兩個最主要的彙編器是 Nasm(free, Netwide Assembler)和 GAS(free, Gnu Assembler),
後一個和 GCC 結合在一起. 在這篇文章裡我將集中在 Nasm 上, 把 GAS 放在後面,因為它使用 AT&T 的語法, 需要一個長的介紹.
Nasm 呼叫時應該帶上 ELF 格式選項("nasm -f elf hello.asm"); 產生的目標檔案用GCC 來連結("gcc hello.o"), 產生最終的 ELF 二進位制程式碼. 下面的這個指令碼可用來編譯 ASM 的模組; 我儘量把它寫得簡單, 所以所有它做的就是接受傳給它的第一個檔名, 用 Nasm 編譯, 用 GCC 來連結.
#!/bin/sh
# assemble.sh =========================================================
outfile=${1%%.*}
tempfile=asmtemp.o
nasm -o $tempfile -f elf $1
gcc $tempfile -o $outfile
rm $tempfile -f
#EOF =================================================================
基本知識:
----------
當然最好的就是在瞭解系統細節之前從一個例子開始. 這裡是一個最基本的"hello-word" 形式的程式:
; asmhello.asm ========================================================
global main
extern printf
section .data
msg db "Helloooooo, nurse!",0Dh,0Ah,0
section .text
main:
push dword msg
call printf
pop eax
ret
; EOF =================================================================
綱要: "global main" 必須宣告為全域性的(global) -- 並且既然我們用 GCC 來連結,進入點必須以 "main" 來命名 -- 從而裝入系統. "extern printf" 只是一個宣告,為以後在程式中呼叫; 注意這是必須的; 引數的大小不需要宣告. 我已經把這個例子用標準的 .data, .text 分節, 但這不是嚴格必須的 -- 可能只需要一個 .text段, 就像在 DOS 下一樣.
在程式碼的主體部分, 你必須把引數壓棧來傳遞給呼叫. 在 Nasm 裡, 你必須宣告所有不明確資料的大小; 因此就有 "dword" 這個限定詞. 注意和其他彙編器一樣,Nasm 假設所有的記憶體/標號的引用都指的是記憶體地址或者標號, 而不是它的內容.
因而, 指明字串 msg 的地址, 你應該使用 push dword msg, 指明字串 msg 的內容, 應該用 push dword [msg] (這隻能包含 msg 的前四個位元組). 因為 printf
需要一個指向字串的指標, 我們應該指明 msg 的地址.
呼叫 printf 非常的直接. 注意每一次呼叫後你必須把棧清除(見下); 所以 PUSH 了一個
dword 後, 我從棧裡把一個 dword POP 進一個無用的暫存器. Linux 程式只簡單的用一個 RET 來返回系統, 由於每個程式都是 shell(或者是 PID)的產物, 所以程式結束後把 控制權還給它.
注意到在 Linux 下, 你是在 "API" 或中斷服務的場所裡使用系統帶來的標準共享庫.
所有的外部引用由 GCC 管理, 它給 asm 程式設計師節省了大部分的工作. 一旦你習慣了基本的技巧, Linux 下的彙編程式設計實際上要比 DOS 簡單的多.
C 呼叫的語法
--------------------
Linux 使用 C 的呼叫模式 -- 意味著引數以相反的順序進棧(最後一個最先), 呼叫者必須清
除棧. 你可以從棧裡把值 pop 出來:
push dword szText
call puts
pop ecx
或者直接修改 ESP:
push dword szText
call puts
add esp, 4
呼叫的返回值在 eax 或 edx:eax 如果值大於 32 位的話. EBP, ESI, EDI, EBX 由呼叫者
儲存和恢復. 你必須儲存你要使用的暫存器, 像下面這樣:
; loop.asm =================================================================
global main
extern printf
section .text
msg db "HoodooVoodoo WeedooVoodoo",0Dh,0Ah,0
main:
mov ecx, 0Ah
push dword msg
looper:
call printf
loop looper
pop eax
ret
; EOF ================================================================
粗一看, 非常簡單: 因為你在 10 個 printf() 呼叫用的是同一個字串, 你不需要清除棧. 但當你編譯以後, 迴圈不會停止. 為什麼? 因為 printf() 裡什麼地方用了 ECX 但沒有儲存. 使你的迴圈正確的工作, 你必須在呼叫之前儲存 ECX 的值, 呼叫之後恢復它, 像這樣:
; loop.asm ================================================================
global main
extern printf
section .text
msg db "HoodooVoodoo WeedooVoodoo",0Dh,0Ah,0
main:
mov ecx, 0Ah
looper:
push ecx ;save Count
push dword msg
call printf
pop eax ;cleanup stack
pop ecx ;restore Count
loop looper
ret
; EOF ================================================================
I/O 埠程式設計
--------------------
但直接訪問硬體會怎麼樣呢? 在 Linux 下你需要一個核心模式的驅動程式來做這些工作... 這意味著你的程式必須分成兩個部分, 一個核心模式提供硬體直接操作的功能, 其他的使用者模式提供介面. 一個好訊息就是你仍然可以在使用者模式的程式中使用IN/OUT 來訪問埠.
要訪問埠你的程式必須取得系統的同意; 要做這個, 你必須呼叫 ioperm(). 這個函式只能被有 root 許可權的使用者使用, 所以你必須用 setuid() 使程式到 root 或者直接執行在 root 下. ioperm() 的語法是這樣:
ioperm( long StartingPort#, long #Ports, BOOL ToggleOn-Off)
StartingPort# 指明要訪問的第一個埠值(0 是埠 0h, 40h 是埠 40h, 等等),#Ports
指明要訪問多少個埠(也就是說, StartingPort# = 30h, #Port = 10, 可以訪問埠
30h - 39h), ToggleOn-Off 如果是 TRUE(1) 就能夠訪問, 是 FALSE(0) 就不能訪問.
一旦呼叫了 ioperm(), 要求的埠就和平常一樣訪問. 程式可以呼叫 ioperm() 任意多次,
而不需要在後來呼叫 ioperm()(但下面的例子這樣做了), 因為系統會處理這些.
; io.asm ==============================================================
=
BITS 32
GLOBAL szHello
GLOBAL main
EXTERN printf
EXTERN ioperm
SECTION .data
szText1 db Enabling I/O Port Access,0Ah,0Dh,0
szText2 db Disabling I/O Port Acess,0Ah,0Dh,0
szDone db Done!,0Ah,0Dh,0
szError db Error in ioperm() call!,0Ah,0Dh,0
szEqual db Output/Input bytes are equal.,0Ah,0Dh,0
szChange db Output/Input bytes changed.,0Ah,0Dh,0
SECTION .text
main:
push dword szText1
call printf
pop ecx
enable_IO:
push word 1 ; enable mode
push dword 04h ; four ports
push dword 40h ; start with port 40
call ioperm ; Must be SUID "root" for this call!
add ESP, 10 ; cleanup stack (method 1)
cmp eax, 0 ; check ioperm() results
jne Error
;---------------------------------------Port Programming Part--------------
SetControl:
mov al, 96 ; R/W low byte of Counter2, mode 3
out 43h, al ; port 43h = control register
WritePort:
mov bl, 0EEh ; value to send to speaker timer
mov al, bl
out 42h, al ; port 42h = speaker timer
ReadPort:
in al, 42h
cmp al, bl ; byte should have changed--this IS a timer
jne ByteChanged
BytesEqual:
push dword szEqual
call printf
pop ecx
jmp disable_IO
ByteChanged:
push dword szChange
call printf
pop ecx
;---------------------------------------End Port Programming Part----------
disable_IO:
push dword szText2
call printf
pop ecx
push word 0 ; disable mode
push dword 04h ; four ports
push dword 40h ; start with port 40h
call ioperm
pop ecx ;cleanup stack (method 2)
pop ecx
pop cx
cmp eax, 0 ; check ioperm() results
jne Error
jmp Exit
Error:
push dword szError
call printf
pop ecx
Exit:
ret
; EOF ======================================================================
在 Linux 下使用中斷
-------------------------
Linux 是一個執行在保護模式下的共享庫的環境, 意味著沒有中斷服務, Right?
錯了. 我注意到在 GAS 的例子原始碼中用了 INT 80, 註釋是 "sys_write(ebx, ecx, ed
x)".
這個函式是 Linux 系統呼叫介面的一部分, 意思是 INT 80 必須是到達系統呼叫服務
的門戶. 在 Linux 原始碼中到處看時(忽略從不要使用 INT 80 介面的警告, 因為函式號
可能隨時改變), 我發現 "系統呼叫號(system call numbers)" -- 就是說, 傳給 INT
80
的 # 對應著一個系統呼叫子程式 -- 在 UNISTD.H 中. 一共有 189 個, 所以我不會在
這裡列出來...但如果你在 Linux 做彙編, 給自己做個好事, 列印出來吧.
當呼叫 INT 80 時, eax 設為用呼叫的功能號. 傳給系統呼叫則程式的引數必須按順序
放在下列暫存器中:
ebx, ecx, edx, esi, edi
這樣, 第一個引數就在 ebx 裡, 第二個在 ecx 裡... 注意在一個系統呼叫程式裡, 不
是
用棧來傳遞引數. 呼叫的返回值在 eax 裡.
還有, INT 80 介面和一般的呼叫一樣. 下面的這個程式就演示了 INT 80h 的使用. 這
個
程式檢查並顯示了它自己的 PID. 注意 使用 printf() 格式化字串 -- 這個呼叫的
C 結構
是:
printf( "%d ", curr_PID);
也要注意結束符在彙編裡不一定可靠, 我常用十六進位制(0Ah, 0Dh)代表 CRLF.
;pid.asm====================================================================
BITS 32
GLOBAL main
EXTERN printf
SECTION .data
szText1 db Getting Current Process ID...,0Ah,0Dh,0
szDone db Done!,0Ah,0Dh,0
szError db Error in int 80!,0Ah,0Dh,0
szOutput db \%d,0Ah,0Dh,0 ;printf() 的格式字串
SECTION .text
main:
push dword szText1 ;開始資訊
call printf
pop ecx
GetPID:
mov eax, dword 20 ; getpid() 系統呼叫
int 80h ; 系統呼叫中斷
cmp eax, 0 ; 沒有 PID 0 !
jb Error
push eax ; 把返回值傳遞給 printf
push dword szOutput ; 把格式字串傳遞給 printf
call printf
pop ecx ; 清除棧
pop ecx
push dword szDone ; 結束資訊
call printf
pop ecx
jmp Exit
Error:
push dword szError
call printf
pop ecx
Exit:
ret
; EOF =====================================================================
最後的話
-----------
大多數的麻煩來自對 Nasm 的習慣上. 而 nasm 帶有手冊, 但預設是不安裝的,
所以你必須把它從
/user/local/bin/nasm-0.97/nasm.man
移(cp 或 mv)到
/usr/local/man/man1/nasm.man.
格式有點亂, 可以很簡單的用 nroff 指示符來解決. 但它不會給你 Nasm 的整個文
檔; 要解決這個問題, 把 nasmdoc.txt 從
/usr/local/bin/nasm-0.97/doc/nasmdoc.txt
複製到
/usr/local/man/man1/nasmdoc.man
現在你可以用 man nasm, man nasmdoc 來看 nasm 的手冊和文件了
想得到更多的資訊, 查查這裡:
Linux Assembly Language HOWTO (Linux 組合語言 HOWTO)
Linux I/O Port Programming Mini-HOWTO (Linux I/O 埠程式設計 Mini-HOWTO)
Jans Linux & Assembler HomePage (
我也要感謝 Jeff Weeks(, 在我找到 Jan 的網頁之前
給了我一些 GAS 的 hello-world 程式碼。
編譯和連結
---------------------
Linux 下兩個最主要的彙編器是 Nasm(free, Netwide Assembler)和 GAS(free, Gnu Assembler),
後一個和 GCC 結合在一起. 在這篇文章裡我將集中在 Nasm 上, 把 GAS 放在後面,因為它使用 AT&T 的語法, 需要一個長的介紹.
Nasm 呼叫時應該帶上 ELF 格式選項("nasm -f elf hello.asm"); 產生的目標檔案用GCC 來連結("gcc hello.o"), 產生最終的 ELF 二進位制程式碼. 下面的這個指令碼可用來編譯 ASM 的模組; 我儘量把它寫得簡單, 所以所有它做的就是接受傳給它的第一個檔名, 用 Nasm 編譯, 用 GCC 來連結.
#!/bin/sh
# assemble.sh =========================================================
outfile=${1%%.*}
tempfile=asmtemp.o
nasm -o $tempfile -f elf $1
gcc $tempfile -o $outfile
rm $tempfile -f
#EOF =================================================================
基本知識:
----------
當然最好的就是在瞭解系統細節之前從一個例子開始. 這裡是一個最基本的"hello-word" 形式的程式:
; asmhello.asm ========================================================
global main
extern printf
section .data
msg db "Helloooooo, nurse!",0Dh,0Ah,0
section .text
main:
push dword msg
call printf
pop eax
ret
; EOF =================================================================
綱要: "global main" 必須宣告為全域性的(global) -- 並且既然我們用 GCC 來連結,進入點必須以 "main" 來命名 -- 從而裝入系統. "extern printf" 只是一個宣告,為以後在程式中呼叫; 注意這是必須的; 引數的大小不需要宣告. 我已經把這個例子用標準的 .data, .text 分節, 但這不是嚴格必須的 -- 可能只需要一個 .text段, 就像在 DOS 下一樣.
在程式碼的主體部分, 你必須把引數壓棧來傳遞給呼叫. 在 Nasm 裡, 你必須宣告所有不明確資料的大小; 因此就有 "dword" 這個限定詞. 注意和其他彙編器一樣,Nasm 假設所有的記憶體/標號的引用都指的是記憶體地址或者標號, 而不是它的內容.
因而, 指明字串 msg 的地址, 你應該使用 push dword msg, 指明字串 msg 的內容, 應該用 push dword [msg] (這隻能包含 msg 的前四個位元組). 因為 printf
需要一個指向字串的指標, 我們應該指明 msg 的地址.
呼叫 printf 非常的直接. 注意每一次呼叫後你必須把棧清除(見下); 所以 PUSH 了一個
dword 後, 我從棧裡把一個 dword POP 進一個無用的暫存器. Linux 程式只簡單的用一個 RET 來返回系統, 由於每個程式都是 shell(或者是 PID)的產物, 所以程式結束後把 控制權還給它.
注意到在 Linux 下, 你是在 "API" 或中斷服務的場所裡使用系統帶來的標準共享庫.
所有的外部引用由 GCC 管理, 它給 asm 程式設計師節省了大部分的工作. 一旦你習慣了基本的技巧, Linux 下的彙編程式設計實際上要比 DOS 簡單的多.
C 呼叫的語法
--------------------
Linux 使用 C 的呼叫模式 -- 意味著引數以相反的順序進棧(最後一個最先), 呼叫者必須清
除棧. 你可以從棧裡把值 pop 出來:
push dword szText
call puts
pop ecx
或者直接修改 ESP:
push dword szText
call puts
add esp, 4
呼叫的返回值在 eax 或 edx:eax 如果值大於 32 位的話. EBP, ESI, EDI, EBX 由呼叫者
儲存和恢復. 你必須儲存你要使用的暫存器, 像下面這樣:
; loop.asm =================================================================
global main
extern printf
section .text
msg db "HoodooVoodoo WeedooVoodoo",0Dh,0Ah,0
main:
mov ecx, 0Ah
push dword msg
looper:
call printf
loop looper
pop eax
ret
; EOF ================================================================
粗一看, 非常簡單: 因為你在 10 個 printf() 呼叫用的是同一個字串, 你不需要清除棧. 但當你編譯以後, 迴圈不會停止. 為什麼? 因為 printf() 裡什麼地方用了 ECX 但沒有儲存. 使你的迴圈正確的工作, 你必須在呼叫之前儲存 ECX 的值, 呼叫之後恢復它, 像這樣:
; loop.asm ================================================================
global main
extern printf
section .text
msg db "HoodooVoodoo WeedooVoodoo",0Dh,0Ah,0
main:
mov ecx, 0Ah
looper:
push ecx ;save Count
push dword msg
call printf
pop eax ;cleanup stack
pop ecx ;restore Count
loop looper
ret
; EOF ================================================================
I/O 埠程式設計
--------------------
但直接訪問硬體會怎麼樣呢? 在 Linux 下你需要一個核心模式的驅動程式來做這些工作... 這意味著你的程式必須分成兩個部分, 一個核心模式提供硬體直接操作的功能, 其他的使用者模式提供介面. 一個好訊息就是你仍然可以在使用者模式的程式中使用IN/OUT 來訪問埠.
要訪問埠你的程式必須取得系統的同意; 要做這個, 你必須呼叫 ioperm(). 這個函式只能被有 root 許可權的使用者使用, 所以你必須用 setuid() 使程式到 root 或者直接執行在 root 下. ioperm() 的語法是這樣:
ioperm( long StartingPort#, long #Ports, BOOL ToggleOn-Off)
StartingPort# 指明要訪問的第一個埠值(0 是埠 0h, 40h 是埠 40h, 等等),#Ports
指明要訪問多少個埠(也就是說, StartingPort# = 30h, #Port = 10, 可以訪問埠
30h - 39h), ToggleOn-Off 如果是 TRUE(1) 就能夠訪問, 是 FALSE(0) 就不能訪問.
一旦呼叫了 ioperm(), 要求的埠就和平常一樣訪問. 程式可以呼叫 ioperm() 任意多次,
而不需要在後來呼叫 ioperm()(但下面的例子這樣做了), 因為系統會處理這些.
; io.asm ==============================================================
=
BITS 32
GLOBAL szHello
GLOBAL main
EXTERN printf
EXTERN ioperm
SECTION .data
szText1 db Enabling I/O Port Access,0Ah,0Dh,0
szText2 db Disabling I/O Port Acess,0Ah,0Dh,0
szDone db Done!,0Ah,0Dh,0
szError db Error in ioperm() call!,0Ah,0Dh,0
szEqual db Output/Input bytes are equal.,0Ah,0Dh,0
szChange db Output/Input bytes changed.,0Ah,0Dh,0
SECTION .text
main:
push dword szText1
call printf
pop ecx
enable_IO:
push word 1 ; enable mode
push dword 04h ; four ports
push dword 40h ; start with port 40
call ioperm ; Must be SUID "root" for this call!
add ESP, 10 ; cleanup stack (method 1)
cmp eax, 0 ; check ioperm() results
jne Error
;---------------------------------------Port Programming Part--------------
SetControl:
mov al, 96 ; R/W low byte of Counter2, mode 3
out 43h, al ; port 43h = control register
WritePort:
mov bl, 0EEh ; value to send to speaker timer
mov al, bl
out 42h, al ; port 42h = speaker timer
ReadPort:
in al, 42h
cmp al, bl ; byte should have changed--this IS a timer
jne ByteChanged
BytesEqual:
push dword szEqual
call printf
pop ecx
jmp disable_IO
ByteChanged:
push dword szChange
call printf
pop ecx
;---------------------------------------End Port Programming Part----------
disable_IO:
push dword szText2
call printf
pop ecx
push word 0 ; disable mode
push dword 04h ; four ports
push dword 40h ; start with port 40h
call ioperm
pop ecx ;cleanup stack (method 2)
pop ecx
pop cx
cmp eax, 0 ; check ioperm() results
jne Error
jmp Exit
Error:
push dword szError
call printf
pop ecx
Exit:
ret
; EOF ======================================================================
在 Linux 下使用中斷
-------------------------
Linux 是一個執行在保護模式下的共享庫的環境, 意味著沒有中斷服務, Right?
錯了. 我注意到在 GAS 的例子原始碼中用了 INT 80, 註釋是 "sys_write(ebx, ecx, ed
x)".
這個函式是 Linux 系統呼叫介面的一部分, 意思是 INT 80 必須是到達系統呼叫服務
的門戶. 在 Linux 原始碼中到處看時(忽略從不要使用 INT 80 介面的警告, 因為函式號
可能隨時改變), 我發現 "系統呼叫號(system call numbers)" -- 就是說, 傳給 INT
80
的 # 對應著一個系統呼叫子程式 -- 在 UNISTD.H 中. 一共有 189 個, 所以我不會在
這裡列出來...但如果你在 Linux 做彙編, 給自己做個好事, 列印出來吧.
當呼叫 INT 80 時, eax 設為用呼叫的功能號. 傳給系統呼叫則程式的引數必須按順序
放在下列暫存器中:
ebx, ecx, edx, esi, edi
這樣, 第一個引數就在 ebx 裡, 第二個在 ecx 裡... 注意在一個系統呼叫程式裡, 不
是
用棧來傳遞引數. 呼叫的返回值在 eax 裡.
還有, INT 80 介面和一般的呼叫一樣. 下面的這個程式就演示了 INT 80h 的使用. 這
個
程式檢查並顯示了它自己的 PID. 注意 使用 printf() 格式化字串 -- 這個呼叫的
C 結構
是:
printf( "%d ", curr_PID);
也要注意結束符在彙編裡不一定可靠, 我常用十六進位制(0Ah, 0Dh)代表 CRLF.
;pid.asm====================================================================
BITS 32
GLOBAL main
EXTERN printf
SECTION .data
szText1 db Getting Current Process ID...,0Ah,0Dh,0
szDone db Done!,0Ah,0Dh,0
szError db Error in int 80!,0Ah,0Dh,0
szOutput db \%d,0Ah,0Dh,0 ;printf() 的格式字串
SECTION .text
main:
push dword szText1 ;開始資訊
call printf
pop ecx
GetPID:
mov eax, dword 20 ; getpid() 系統呼叫
int 80h ; 系統呼叫中斷
cmp eax, 0 ; 沒有 PID 0 !
jb Error
push eax ; 把返回值傳遞給 printf
push dword szOutput ; 把格式字串傳遞給 printf
call printf
pop ecx ; 清除棧
pop ecx
push dword szDone ; 結束資訊
call printf
pop ecx
jmp Exit
Error:
push dword szError
call printf
pop ecx
Exit:
ret
; EOF =====================================================================
最後的話
-----------
大多數的麻煩來自對 Nasm 的習慣上. 而 nasm 帶有手冊, 但預設是不安裝的,
所以你必須把它從
/user/local/bin/nasm-0.97/nasm.man
移(cp 或 mv)到
/usr/local/man/man1/nasm.man.
格式有點亂, 可以很簡單的用 nroff 指示符來解決. 但它不會給你 Nasm 的整個文
檔; 要解決這個問題, 把 nasmdoc.txt 從
/usr/local/bin/nasm-0.97/doc/nasmdoc.txt
複製到
/usr/local/man/man1/nasmdoc.man
現在你可以用 man nasm, man nasmdoc 來看 nasm 的手冊和文件了
想得到更多的資訊, 查查這裡:
Linux Assembly Language HOWTO (Linux 組合語言 HOWTO)
Linux I/O Port Programming Mini-HOWTO (Linux I/O 埠程式設計 Mini-HOWTO)
Jans Linux & Assembler HomePage (
我也要感謝 Jeff Weeks(, 在我找到 Jan 的網頁之前
給了我一些 GAS 的 hello-world 程式碼。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617542/viewspace-947282/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Linux 中 x86 的內聯彙編(轉)Linux
- STM彙編程式設計程式設計
- 常用的x86彙編指令
- x86彙編之棧與子程式呼叫
- STM32彙編程式設計程式設計
- 【實驗】 ARM彙編程式設計程式設計
- X86彙編快速入門
- 三個程式設計中遇到的小問題彙編程式設計
- Linux 程式設計之Shell程式設計(轉)Linux程式設計
- 彙編學習小記(二)-順序程式設計程式設計
- 彙編實驗小記(五)-迴圈程式設計程式設計
- 彙編debug程式跳轉指令的方法
- x86彙編反編譯到c語言之——(2)if語句編譯C語言
- Linux的shell程式設計(一)(轉)Linux程式設計
- Linux的shell程式設計(二)(轉)Linux程式設計
- Linux的shell程式設計(三)(轉)Linux程式設計
- Linux的shell程式設計(四)(轉)Linux程式設計
- Linux下的OpenGL程式設計(轉)Linux程式設計
- Linux核心程式設計(阻塞程式)(轉)Linux程式設計
- shellcode轉換成彙編程式碼
- Linux下彙編偵錯程式GDB的使用薦Linux
- Linux核心模組的程式設計方法(轉)Linux程式設計
- linux彙編指令Linux
- linux驅動程式設計(轉)Linux程式設計
- Linux程式設計之一(轉)Linux程式設計
- Linux程式設計之三(轉)Linux程式設計
- Linux程式設計之四(轉)Linux程式設計
- Linux防火牆程式設計(轉)Linux防火牆程式設計
- Linux Unicode 程式設計(轉)LinuxUnicode程式設計
- Linux守護程式的程式設計實現(轉)Linux程式設計
- 計算機執行彙編程式碼的原理計算機
- 飛思卡爾微控制器PIT彙編程式設計(一)程式設計
- Win32彙編教程二 Win32彙編程式的結構和語法 (轉)Win32
- RealPlayer for Linux/x86(轉)Linux
- Linux核心模組程式設計--阻塞程式(轉)Linux程式設計
- 彙編跳轉指令
- 32位彙編第一講x86和8086的區別,以及OllyDbg偵錯程式的使用
- Linux下的shell程式設計入門(轉)Linux程式設計