2012-12-31 72 views
1

我有這個函數,主要由inline asm組成。'ret'指令訪問衝突

​​

而且一旦運行,我得到一個訪問衝突的返回指令。

我使用的是VC++ 6,它有時可能意味着指向上面的行,所以可能在'pop esp'上。 如果你能幫助我,那會很棒。 謝謝,iDomo。

+0

調用'malloc'後清除堆棧中的大小('eax')。並且讓'ret'離開你的代碼,讓編譯器處理那部分。 – DCoder

+1

'ret'崩潰?堆棧粉碎。 *飛走* – 2012-12-31 22:08:46

+0

使用內聯彙編時,編譯器是否自動保存所需的寄存器?如果沒有,你需要用'push's在開始處保存'ESI','EDI','EBX','EBP'和'ESP'(最後用'pop'來修改它們) ' – Gunner

回答

8

您無法正確管理堆棧指針。特別是,您致電malloc會使堆疊不平衡,並且您的pop esp最終會將錯誤的值彈入esp。因此,當您嘗試從無效堆棧中對ret進行訪問衝突時(CPU無法讀取返回地址)。目前還不清楚你爲什麼推動和彈出esp;那完成任何事情。

0

我已經想出了自己的答案。

對於那些誰都有過這樣的相同,或相似的問題:

實際的例外是用戶代碼後存在的,當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 
    } 
} 
+0

我剛剛向你的代碼發佈了一些改進。 –

0

當你發現,你永遠不應該使用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。

+0

我是爲了解釋的目的而做的,所以優化它對我沒有任何好處。感謝壽。 – iDomo

+0

它從不會傷害到簡化代碼壽'。添加了一些評論,並糾正了一些錯別字。 –