我有這個函數,主要由inline asm組成。'ret'指令訪問衝突
而且一旦運行,我得到一個訪問衝突的返回指令。
我使用的是VC++ 6,它有時可能意味着指向上面的行,所以可能在'pop esp'上。 如果你能幫助我,那會很棒。 謝謝,iDomo。
我有這個函數,主要由inline asm組成。'ret'指令訪問衝突
而且一旦運行,我得到一個訪問衝突的返回指令。
我使用的是VC++ 6,它有時可能意味着指向上面的行,所以可能在'pop esp'上。 如果你能幫助我,那會很棒。 謝謝,iDomo。
您無法正確管理堆棧指針。特別是,您致電malloc
會使堆疊不平衡,並且您的pop esp
最終會將錯誤的值彈入esp
。因此,當您嘗試從無效堆棧中對ret
進行訪問衝突時(CPU無法讀取返回地址)。目前還不清楚你爲什麼推動和彈出esp
;那完成任何事情。
我已經想出了自己的答案。
對於那些誰都有過這樣的相同,或相似的問題:
實際的例外是用戶代碼後存在的,當VC++自動彈出/恢復寄存器進入狀態被稱爲函數之前。由於我在調用malloc時未命中對齊堆棧指針,因此從堆棧彈出時存在訪問衝突。我在編輯器中看不到它,因爲它不是我的代碼,所以它只是作爲函數中最後一個代碼顯示出來。
要解決此問題,只需在您進行的調用後添加esp(前一個調用的參數大小)即可。
固定碼:
long *toarrayl(int members, ...){
__asm{
mov eax, members
imul eax, 4
push eax
call malloc
add esp, 4
mov edx, eax
mov edi, eax
xor ecx, ecx
xor esi, esi
loopx:
cmp ecx, members
je done
mov esi, 4
imul esi, ecx
add esi, ebp
mov eax, [esi+0xC]
mov [edi], eax
inc ecx
add edi, 4
jmp loopx
done:
mov eax, edx
ret
}
//return (long*)0;
}
優化代碼:
long *toarrayl(int members, ...){
__asm{
mov eax, members
shl eax, 2
push eax
call malloc
add esp, 4
;cmp eax, 0
;je _error
mov edi, eax
mov ecx, members
lea esi, [ebp+0xC]
loopx:
mov edx, [esi]
mov [edi], edx
add edi, 4
add esi, 4
dec ecx
jnz loopx
}
}
我剛剛向你的代碼發佈了一些改進。 –
當你發現,你永遠不應該使用ESP的指令POP - 當你看到,在代碼中,你知道的東西極其錯誤已經發生了。當然,在彙編代碼中調用malloc也是一件不好的事情 - 例如,你忘記檢查它是否返回NULL,所以你可能會崩潰。堅持在你的彙編程序之外 - 並且檢查NULL,調試「在mycode.c文件的第54行無法分配內存」比「彙編器中的某處」更容易,我們得到了一個
這裏有一些改進的建議,這應加快你的循環一點:
long *toarrayl(int members, ...){
__asm{
mov eax, members
imul eax, 4
push eax
call malloc
add esp, 4
mov edx, eax
mov edi, eax
mov ecx, members
lea esi, [ebp+0xc]
loopx:
mov eax, [esi]
mov [edi], eax
add edi, 4
add esi, 4
dec ecx
jnz loopx
mov lret, eax
ret
}
}
改進:在每一個循環乘以4只刪除增量esi
而不是在ECX使用遞減,而不是increament,並在循環之前與會員加載它。 。這允許使用循環中的一次跳轉,而不是兩次。刪除redux從edx移動到eax。直接使用eax。
我是爲了解釋的目的而做的,所以優化它對我沒有任何好處。感謝壽。 – iDomo
它從不會傷害到簡化代碼壽'。添加了一些評論,並糾正了一些錯別字。 –
調用'malloc'後清除堆棧中的大小('eax')。並且讓'ret'離開你的代碼,讓編譯器處理那部分。 – DCoder
'ret'崩潰?堆棧粉碎。 *飛走* – 2012-12-31 22:08:46
使用內聯彙編時,編譯器是否自動保存所需的寄存器?如果沒有,你需要用'push's在開始處保存'ESI','EDI','EBX','EBP'和'ESP'(最後用'pop'來修改它們) ' – Gunner