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