Intel處理器系列俗稱x86,開始時它是第一代單芯片。16位爲處理器之一。
8086是第一代,也是彙編課程中學習的處理器型號。html
GCC爲32位執行的默認調用。(gcc -m32)git
在GCC中得到彙編代碼與反彙編
得到彙編代碼:gcc –S xxx.c –o xxx.s。
反彙編(將二進制目標文件還原爲彙編代碼)objdump –d xxx.o。
注:64位機器上想要獲得32位代碼:gcc –m32 –S xxx.c。less
二進制文件能夠用od 命令查看,也能夠用gdb的x命令查看。(WinHex)有些輸出內容過多,咱們可使用 more或less命令結合管道查看,也可使用輸出重定向來查看。
od code.o | more od code.o > code.txt
函數
要查看目標代碼文件的內容,最有價值的是反彙編器。
objdump -d code.o
oop
機器代碼和它的反彙編表示的一些特性:
IA32指令長度從1到15個字節不等
設計指令格式的方式是,從某個給定位置開始,能夠將字節惟一的解碼成機器指令
反彙編器只是基於機器代碼文件中的字節序列來肯定彙編代碼,不須要訪問程序的源代碼或彙編代碼
反彙編器使用的指令命名規則與GCC生成的彙編代碼使用的有些差異學習
數據傳送指令
MOV類由三條指令組成:
movb 傳送字節
movw 傳送字
movl 傳送雙字
操做數:
MOV reg/mem, imm ;當即數寄存器或存儲器 MOV reg/mem/seg, reg ;寄存器的值寄存器/內存/段寄存器 MOV reg/seg, mem ;內存單元的值寄存器/段寄存器 MOV reg/mem, seg ;段寄存器的值寄存器/內存單元 IA32的限制:兩個操做數都不能指向存儲器。
測試
push&pop
堆棧:
1.後進先出
2.棧指針指向棧頂元素
3.棧朝低地址方向增加
壓棧push:
格式PUSH r16/m16/seg
功能:
第一步:SP←SP-2 ;堆棧指針SP上移
第二步:(SS):(SP)←r16/m16/seg ;字操做數存入堆棧頂部
出棧pop:
格式POP r16/m16/seg
功能:
第一步:r16/m16/seg← (SS):(SP) ;棧頂的一個字傳送到指定的目的操做數
第二步:SP←SP+2 ;堆棧指針SP下移,指向新的棧頂ui
leal,是movl指令的變形,對比彙編中的LEA指令學習。
其實是將有效地址寫入目的操做數。編碼
INC 加1 DEC 減1 NEG 取負 NOT 取補
只有一個操做數,既是源又是目的,能夠是一個寄存器,或者存儲器位置。.net
ADD 加 SUB 減 IMUL 乘 XOR 異或 OR 或 AND 與
第一個操做數能夠是當即數、寄存器或者存儲器位置
第二個操做數既是源也是又是目的。能夠是寄存器或者存儲器位置,可是不能同時是存儲器位置。
注意操做的順序:第二個操做數 操做符 第一個操做數
SAL 左移 SHL 左移(等同於SAL) SAR 算術右移 SHR 邏輯右移
imull 雙操做數 從兩個32位操做數產生一個32位的乘積。
乘積不截斷
mull 無符號數乘法 imull 有符號數乘法 要求一個參數必須在寄存器%eax中,另外一個做爲指令的源操做數給出。 乘積的高32位在%edx中,低32位在%eax中。
除法
有符號除法
idivl 操做數 將DX:AX中的64位數做爲被除數,操做數中爲除數 結果:商在AX中,餘數在DX中。
無符號除法
divl指令 一般會事先設定寄存器%edx爲0。
CF:進位標誌。最近操做使最高位產生進位。用於檢查無符號操做數的溢出。
ZF:零標誌。最近操做結果爲0。
SF:符號標誌。最近操做獲得的結果爲負數。
OF:溢出標誌。最近操做致使一個補碼溢出。
使用方法:根據條件碼的某個組合,將一個字節設置爲0或1。
SET指令:執行比較指令,根據計算t=a-b
的結果設置條件碼
能夠條件跳轉到程序的某個其餘部分,能夠有條件的傳送數據。
無條件跳轉
直接跳轉:跳轉目標是做爲指令的一部分編碼的。
間接跳轉:跳轉目標是從寄存器或存儲器位置中讀出的。
當執行與PC相關的尋址時,程序計數器的值是跳轉指令後面的那條指令的地址,而不是跳轉指令自己的地址。
將條件表達式和語句從c語言翻譯成機器語言,最經常使用的方式就是結合有條件和無條件跳轉。
if(test-expr) then-statement else else-statement (注:test-expr 整數表達式[假/真])
彙編中能夠用條件測試和跳轉組合起來實現循環的效果,可是大多數彙編器中都要先將其餘形式的循環轉換成do-while格式。
do body-statement while(test-expr);
翻譯成以下條件和goto語句:
loop: body-statement t = test-expr; if(t) goto loop;
while (test-expr) body-statement
轉換成 do-while 形式:
if(!test-expr) goto done; do body-statement while(test-expr); done:
翻譯成 goto 形式:
t = test-expr; if(!t) goto done: loop: body-statement t = test-expr; if(t) goto loop; done:
for(init-expr;test-expr;update-expr) body-statement
同while形式
init-expr; while(test-expr){ body-statement update-expr; }
轉換成 do-while 形式:
init-expr; if(!test-expr) goto done; do{ body-statement update-expr; }while(test-expr); done;
轉換成 goto 代碼:
init-expr t = test-expr; if(!t) goto done: loop: body-statement t = test-expr; if(t) goto loop; done:
Switch語句是多重分支的典型,並且使用的是跳轉表這種數據類型,是的搜索的更快更高效。
因此這裏的關鍵就是要領會使用跳轉表是一種很是有效的實現多重分支的方法。
進入,爲過程的局部變量分配空間 將數據(以過程參數和返回值的形式)和控制從代碼的一部分傳遞到另外一部分。 退出,釋放這些空間。
棧幀: 爲單個過程分配的那部分棧
寄存器%ebp爲幀指針 寄存器%esp爲棧指針
棧指針值適當減少能夠分配沒有指定初始值的數據的空間 相似的,能夠經過增長棧指針來釋放空間
call指令
目標:指明被調用過程起始的指令地址。
效果:將返回地址入棧,並跳轉到被調用過程的起始處。
ret指令
從棧中彈出地址,並跳轉到這個位置.
使用這個指令時,棧指針要指向前面call指令存儲返回地址的位置。
leave
這個指令可使棧作好返回的準備
%eax,%edx,%ecx 劃分爲調用者保存寄存器
%ebx,%esi,%edi 劃分爲被調用者保存寄存器
%ebp,%esp 保持寄存器
%eax 保存函數返回值
run(簡寫r): 運行程序,當遇到斷點後,程序會在斷點處中止運行,等待用戶輸入下一步的命令。
continue(簡寫c):繼續執行,到下一個斷點處(或運行結束)
next(簡寫n): 單步跟蹤程序,當遇到函數調用時,直接調用,不進入此函數體;
step(簡寫s):單步調試若是有函數調用,則進入函數;與命令n不一樣,n是不進入調用的函數的
until:運行程序直到退出循環體; / until+行號: 運行至某行
finish: 運行程序,直到當前函數完成返回,並打印函數返回時的堆棧地址和返回值及參數值等信息。
call 函數(參數):調用「函數」,並傳遞「參數」,如:call gdb_test(55)
quit:簡記爲 q ,退出gdb 設置斷點
break n(簡寫b n):在第n行處設置斷點 ;能夠帶上代碼路徑和代碼名稱: bOAGUPDATE.cpp:578)
break func:在函數func()的入口處設置斷點,如:break cb_button
delete 斷點號n:刪除第n個斷點
disable 斷點號n:暫停第n個斷點
enable 斷點號n:開啓第n個斷點
clear 行號n:清除第n行的斷點
info breakpoints(簡寫info b) :顯示當前程序的斷點設置狀況
list(簡寫l):列出程序的源代碼,默認每次顯示10行。
list 行號:將顯示當前文件以「行號」爲中心的先後10行代碼,如:list 12
list 函數名:將顯示「函數名」所在函數的源代碼,如:list main
list :不帶參數,將接着上一次 list 命令的,輸出下邊的內容。
print 表達式:簡記爲 p ,其中「表達式」能夠是任何當前正在被測試程序的有效表達式,好比當前正在調試C語言的程序,那麼「表達式」能夠是任何C語言的有效表達式,包括數字,變量甚至是函數調用。
print a:將顯示整數 a 的值
print ++a:將把 a 中的值加1,並顯示出來
print name:將顯示字符串 name 的值
print gdb_test(22):將以整數22做爲參數調用 gdb_test() 函數
print gdb_test(a):將以變量 a 做爲參數調用 gdb_test() 函數
display 表達式:在單步運行時將很是有用,使用display命令設置一個表達式後,它將在每次單步進行指令後,緊接着輸出被設置的表達式及值。
watch 表達式:設置一個監視點,一旦被監視的「表達式」的值改變,gdb將強行終止正在被調試的程序。
where/bt :當前運行的堆棧列表
set args 參數:指定運行時的參數
show args:查看設置好的參數
info program: 來查看程序的是否在運行,進程號,被暫停的緣由
layout:用於分割窗口,能夠一邊查看代碼,一邊測試
layout src:顯示源代碼窗口
layout asm:顯示反彙編窗口
layout regs:顯示源代碼/反彙編和CPU寄存器窗口
layout split:顯示源代碼和反彙編窗口
Ctrl + L:刷新窗口
C語言編譯器產生的彙編代碼
查看代碼的二進制代碼
將C語言文件編譯成可執行文件並查看可執行文件的二進制內容
將可執行文件反編譯成彙編代碼
將調用函數的棧幀棧底地址入棧,即將bp寄存器的值壓入調用棧中
創建新的棧幀,將被調函數的棧幀棧底地址放入bp寄存器中
https://git.oschina.net/albieh
有很多內容都是在上學期學的彙編基礎上加以鞏固,理解起來比較輕鬆,也遇到了之前許多沒有遇到的命令。
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 16篇 | 400小時 | |
第一週 | 80/80 | 1/1 | 20/20 | |
第二週 | 130/210 | 1/2 | 18/38 | |
第三週 | 300/510 | 1/3 | 22/60 | |
第五週 | 300/810 | 1/4 | 30/90 |