|
編譯器:vc++6.0(因為此種實現(xiàn)依賴編譯器處理) 此處只簡要敘述一下機制。并附部分關(guān)鍵指令序列。
準(zhǔn)備: 1,關(guān)于EBP:稱做?;分羔?。為什么這樣說呢?我們先來看看函數(shù)調(diào)用的過程: 參數(shù)從右到左壓棧。 call指令執(zhí)行,該指令將導(dǎo)致EIP壓棧。 每個函數(shù)前兩句必定是:push ebp mov ebp,esp。則call指令后,跳到被調(diào)函數(shù)出開始執(zhí)行。保存ebp,即ebp壓棧。 局部變量壓棧。一般是sub esp,xxx的形式。
這就是將ebp稱為基指針的原因:ebp-xx訪問的時局部變量;ebp+xx訪問的是參數(shù)。最左邊參數(shù)地址是ebp+8h。ebp坐鎮(zhèn)中間為基準(zhǔn)。
2,函數(shù)返回值統(tǒng)一放入eax中。只要放得下。 3,棧擴展方向為從高地址到低地址。結(jié)構(gòu)內(nèi)的變量存貯方式:低地址對應(yīng)聲明順序靠前的成員。一定要注意這里的區(qū)別!它關(guān)系到反匯編生成的代碼里面的數(shù)字是怎么算出來的。但如果你自己寫匯編代碼就不用考慮這些了。只取成員名即可。 4,不能直接在兩個存儲器變量間用mov指令。
主要原理: 當(dāng)調(diào)用一個返回結(jié)構(gòu)體的函數(shù)時,在vc++下,是這樣處理: 首先sub esp,xx,在堆棧上開辟一個空間。大小為結(jié)構(gòu)體大小。 然后lea eax,[esp-xx],即將結(jié)構(gòu)體在堆棧中的地址送eax。 push 參數(shù)。 push eax。 call 函數(shù)。 被調(diào)用函數(shù)內(nèi)部: routine: push ebp mov ebp,esp
一般是定義一個結(jié)構(gòu)體局部變量: struct aa a; sub esp, sizeof aa
然后處理結(jié)構(gòu)體, . . . . 最后return a。 首先mov eax,[ebp+8h] ;將外面的調(diào)用函數(shù)在堆棧內(nèi)開辟的結(jié)構(gòu)體指針賦予eax。 然后將被調(diào)用函數(shù)在堆棧內(nèi)開辟的結(jié)構(gòu)體內(nèi)的值賦到調(diào)用函數(shù)開辟的結(jié)構(gòu)體內(nèi)。 一般形式是:mov ecx,[ebp-結(jié)構(gòu)體大小] ;賦第一個成員 mov [eax],ecx mov ecx,[ebp-結(jié)構(gòu)體大小+第一個成員大?。紤]對齊)] mov [eax+第一個成員大小],ecx ...... 賦完值后返回: add esp,sizeof aa mov esp,ebp pop ebp ret 此時被調(diào)用函數(shù)在堆棧內(nèi)開辟的結(jié)構(gòu)體空間被銷毀。而eax內(nèi)存放的是調(diào)用函數(shù)在堆棧內(nèi)開辟的結(jié)構(gòu)體空間的指針。 調(diào)用函數(shù)利用eax內(nèi)的指針處理結(jié)構(gòu)體。將堆棧內(nèi)的結(jié)構(gòu)體值賦給其它內(nèi)存變量。此處出現(xiàn)了臨時變量。影響了效率(賦值花費時間)。 |
|
|