亚洲春色中文字幕久久久-三上亚,91精品国产亚一区二区三区,久久久九色综合亚洲成色777,涩涩视频下载,国产午夜亚洲精品午夜鲁丝片,国产精品A一区二区三区腾讯导航,影音先锋色情AV在线看片,蜜臀国产在线视频,极品少妇高潮啪啪无码吴梦梦 ,精品人妻无码一区二区三区手机版

標(biāo)題: 總結(jié)-c語言與匯編 [打印本頁]

作者: 51黑tt    時(shí)間: 2016-3-5 17:02
標(biāo)題: 總結(jié)-c語言與匯編
1. c語言的函數(shù)調(diào)用與對應(yīng)的匯編代碼 1.1 調(diào)用規(guī)則
比如調(diào)用函數(shù) function(parameter1, parameter2, parameter3)
Pascal調(diào)用規(guī)則
_cdecl調(diào)用規(guī)則
_stdcall調(diào)用規(guī)則
PUSH     parameter1
PUSH     parameter2
PUSH     parameter3
CALL      function
PUSH     parameter3
PUSH     parameter2
PUSH     parameter1
CALL      function
ADD       ESP, 0CH
PUSH     parameter3
PUSH     parameter2
PUSH     parameter1
CALL      function
參數(shù)從左到右傳遞壓棧,由被調(diào)用函數(shù)清理堆棧 參數(shù)從右到左傳遞壓棧,由調(diào)用函數(shù)負(fù)責(zé)清理堆棧 參數(shù)從右到左傳遞壓棧,由被調(diào)用函數(shù)負(fù)責(zé)清理堆棧
用于Win16平臺
C/C++調(diào)用標(biāo)準(zhǔn)
Windows API 使用


1.2 匯編代碼 對調(diào)用的方式,舉一個(gè)例子,對c語言常用的printf:

printf(“%d", a);
解析成匯編代碼如:
PUSH  a
PUSH  OFFSET String "%d"
CALL  printf
ADD ESP, 8

CALL指令和RET指令
段內(nèi)調(diào)用
對CALL指令來說,其執(zhí)行的步驟一般包括:

對應(yīng) 的RET指令為:

段間調(diào)用
如果是段間函數(shù)調(diào)用,則CALL的執(zhí)行過程一般是:


對應(yīng)的RET指令執(zhí)行步驟:


被調(diào)用函數(shù)的執(zhí)行步驟
PUSH  EBP ; 保存當(dāng)前堆;積bp,以作返回用
MOVE EBP, ESP ; 將當(dāng)前esp的值賦給ebp,作為新的基址,即進(jìn)入函數(shù)內(nèi)部
SUB ESP, 0CCH ; 將esp往下移動(dòng)一個(gè)范圍,開辟一片新的堆棧空間給當(dāng)前函數(shù)使用
; 這是由于堆棧從高地址往低地址增長,所以,減一個(gè)值意味著開辟了
; 新的空間
................. ; 保存其他寄存器的值
.................
................. ; 恢復(fù)壓棧的其他寄存器的值
MOVE ESP, EBP ; 恢復(fù)esp的值為原來的堆棧棧頂值
POP EBP ; 恢復(fù)堆棧基址為原基址位置
RET

一般來說,函數(shù)的返回值會(huì)放在EAX寄存器中返回。

2. c語言特殊語句塊的匯編代碼
1)For循環(huán)的匯編代碼模板
mov <循環(huán)變量>, <初始值> ; 循環(huán)變量賦初值
jmp B ; 直接跳轉(zhuǎn)到循環(huán)控制測試部分代碼
A: (改動(dòng)循環(huán)變量) ; 修改循環(huán)變量值的部分代碼
......
B: cmp <循環(huán)變量>, <限制變量> ; 將循環(huán)變量的值進(jìn)行測試、跳轉(zhuǎn)
jge 跳出循環(huán) ; 符合終止條件,則跳出循環(huán)體 ; (注意,這里的jl指令可以是其他的jge等,一具判斷條件而定)
(循環(huán)體代碼) ; 否則,進(jìn)入循環(huán)體代碼執(zhí)行
...
jmp A ; 循環(huán)體結(jié)束的最后,是一個(gè)無條件跳轉(zhuǎn)語句,調(diào)回直接
; 修改循環(huán)變量的代碼
2)do循環(huán)的匯編代碼模板
A: (循環(huán)體) ; 直接是循環(huán)體代碼
....
cmp <循環(huán)變量>, <限制變量> ; 判斷是否需要終止循環(huán)
jl <循環(huán)開始處> ; 如果不符合終止條件,直接調(diào)回循環(huán)體開始處繼續(xù)執(zhí)行循環(huán)體
; 代碼(注意,這里的jl指令可以是其他的jge等,一具判斷條件而定)


3) while循環(huán)的匯編代碼模板
A: cmp <循環(huán)變量>, <限制變量> ; 先比較循環(huán)變量,是否需要進(jìn)行循環(huán)
jge B ; 如果滿足停止循環(huán),則直接跳到B,即循環(huán)體后的第一個(gè)指令
(循環(huán)體)
……
jmp A ; 循環(huán)體的最后一條指令,是無條件跳轉(zhuǎn)到循環(huán)控制判斷指令A(yù)處
B: (循環(huán)結(jié)束了)

4)if-else的匯編代碼模板(待續(xù)...)
理解調(diào)用棧最重要的兩點(diǎn)是:棧的結(jié)構(gòu),EBP寄存器的作用。

首先要認(rèn)識到這樣兩個(gè)事實(shí):
   1、一個(gè)函數(shù)調(diào)用動(dòng)作可分解為:零到多個(gè)PUSH指令(用于參數(shù)入棧),一個(gè)CALL指令。CALL指令內(nèi)部其實(shí)還暗含了一個(gè)將返回地址(即CALL指令下一條指令的地址)壓棧的動(dòng)作。
   2、幾乎任何本地編譯器都會(huì)在每個(gè)函數(shù)體之前插入類似如下指令:PUSH EBP; MOV EBP ESP;
即,在程序執(zhí)行到一個(gè)函數(shù)的真正函數(shù)體時(shí),已有以下數(shù)據(jù)順序入棧:參數(shù),返回地址,EBP。
   由此得到類似如下的棧結(jié)構(gòu)(參數(shù)入棧順序跟調(diào)用方式有關(guān),這里以C語言默認(rèn)的CDECL為例):

+| (棧底方向,高位地址) |
| ....................|
| ....................|
| 參數(shù)3                |
| 參數(shù)2                |
| 參數(shù)1                |
| 返回地址             |
-| 上一層[EBP]         |
| 局部變量1            |
| 局部變量2            |
|.....................|

   補(bǔ)充:棧一直隨著函數(shù)調(diào)用的深入,一直想棧頂方向壓下去。每次調(diào)用函數(shù)時(shí)候,先壓函數(shù)參數(shù)(從右往左順序壓),再壓入函數(shù)調(diào)用下條指令的地址(由call完成)。接著進(jìn)入調(diào)用函數(shù)體中先執(zhí)行PUSH EBP; MOV EBP ESP;(一般已經(jīng)由編譯器加入到函數(shù)頭中了),接著就是吧函數(shù)體中的局部變量壓入棧中。再遇到函數(shù)的調(diào)用的嵌套則依此類推。(added by smsong)

  “PUSH EBP”“MOV EBP ESP”這兩條指令實(shí)在大有深意:首先將EBP入棧,然后將棧頂指針ESP賦值給EBP!癕OV EBP ESP”這條指令表面上看是用ESP把EBP原來的值覆蓋了,其實(shí)不然——因?yàn)榻oEBP賦值之前,原EBP值已被壓棧(位于棧頂),而新的EBP又恰恰指向棧頂。
   此時(shí)EBP寄存器就已處于一個(gè)很重要的地位,該寄存器中存儲(chǔ)著棧中的一個(gè)地址(原EBP入棧后的棧頂),從該地址為基準(zhǔn),向上(棧底方向)能獲取返回地址、參數(shù)值,向下(棧頂方向)能獲取函數(shù)局部變量值,而該地址處又存儲(chǔ)著上一層函數(shù)調(diào)用時(shí)的EBP值!
   一般而言,ss:[ebp+4]處為返回地址,ss:[ebp+8]處為第一個(gè)參數(shù)值(最后一個(gè)入棧的參數(shù)值,此處假設(shè)其占用4字節(jié)內(nèi)存),ss:[ebp-4]處為第一個(gè)局部變量,ss:[ebp]處為上一層EBP值。
    由于EBP中的地址處總是“上一層函數(shù)調(diào)用時(shí)的EBP值”,而在每一層函數(shù)調(diào)用中,都能通過當(dāng)時(shí)的EBP值“向上(棧底方向)能獲取返回地址、參數(shù)值,向下(棧頂方向)能獲取函數(shù)局部變量值”。
如此形成遞歸,直至到達(dá)棧底。這就是函數(shù)調(diào)用棧。
編譯器對EBP的使用實(shí)在太精妙了。
從當(dāng)前EBP出發(fā),逐層向上找到任何的EBP是很容易的:
unsigned int _ebp;
__asm _ebp, ebp;
while (not stack bottom)
{
    //...
    _ebp = *(unsigned int*)_ebp;
}
假如要寫一個(gè)簡單的調(diào)試器的話,注意需在被調(diào)試進(jìn)程(而非當(dāng)前進(jìn)程——調(diào)試器進(jìn)程)中讀取內(nèi)存數(shù)據(jù)。
8個(gè)通用寄存器:
      數(shù)據(jù)寄存器:AX,BX,CX,DX
      指針寄存器:SP(堆棧指針),BP(基址指針)
      變址寄存器:SI(原地址),DI(目的地址)
1、通用寄存器
數(shù)據(jù)寄存器,指針寄存器和變址寄存器統(tǒng)稱為通用寄存器。這些寄存器除了各自專門用途外,它們均可用于傳送和暫存數(shù)據(jù),可以保存算術(shù)邏輯運(yùn)算中的操作數(shù)和運(yùn)算結(jié)果。
(1)數(shù)據(jù)寄存器
數(shù)據(jù)寄存器主要用來保存操作數(shù)或運(yùn)算結(jié)果等信息,它們的存在節(jié)省了為存取操作數(shù)所需占用總線和訪問存儲(chǔ)器的時(shí)間。
(2)變址和指針寄存器
變址和指針寄存器主要用于存放某個(gè)存儲(chǔ)單元地址的偏移,或某組存儲(chǔ)單元地址的偏移,即作為存儲(chǔ)器(短)指針使用。作為通用寄存器,它們可以保存16位算術(shù)邏輯運(yùn)算中的操作數(shù)和運(yùn)算結(jié)果,有時(shí)運(yùn)算結(jié)果就是需要的存儲(chǔ)單元地址的偏移。
2、控制寄存器(2個(gè))
(1)指令指針寄存器
8086/8088CPU中的指令指針I(yè)P也是16位的。
指令指針I(yè)P給出接著要執(zhí)行的指令在代碼段中的偏移。
(2)標(biāo)志寄存器
8086/8088CPU中有一個(gè)16位的標(biāo)志寄存器,包含了9個(gè)標(biāo)志,主要用于反映處理器的狀態(tài)和運(yùn)算結(jié)果的某些特征。6個(gè)條件標(biāo)志+3個(gè)方向標(biāo)志
3、段寄存器(4個(gè))
8086/8088CPU依賴其內(nèi)部的四個(gè)段寄存器實(shí)現(xiàn)尋址1M字節(jié)物理地址空間。
8086/8088把1M字節(jié)地址空間分成若干邏輯段,當(dāng)前使用的段值存放在段寄存器中。
由于8086/8088有這四個(gè)段寄存器,所以有四個(gè)當(dāng)前使用段可以直接存取,這四個(gè)當(dāng)前段分別稱為代碼段,數(shù)據(jù)段,堆棧段和附加段。
(1)代碼段
(2)數(shù)據(jù)段
(3)堆棧段
(4)附加段







歡迎光臨 (http://www.denmoz.com/bbs/) Powered by Discuz! X3.1