Нарушение прав доступа по инструкции ‘ret’

У меня есть эта функция, которая состоит в основном из встроенного ассемблера.

long *toarrayl(int members, ...){
__asm{
push esp

mov eax, members
imul eax, 4
push eax
call malloc
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
pop esp
ret
}
}

И после запуска я получаю нарушение прав доступа по инструкции возврата.

Я использую VC ++ 6, и иногда это может означать указание на строку выше, что возможно на «pop esp».
Если бы вы могли помочь мне, это было бы здорово.
Спасибо, Идомо.

1

Решение

Вы не можете правильно управлять указателем стека. В частности, ваш звонок malloc разбалансирует стек, и ваш pop esp в итоге выдает неправильное значение в esp, Следовательно, нарушение прав доступа происходит при попытке ret из недопустимого стека (ЦП не может прочитать адрес возврата). Непонятно, почему вы толкаете и высовываетесь esp; это ничего не дает.

8

Другие решения

Как вы заметили, вы никогда не должны использовать инструкцию POP ESP — когда вы видите это в коде, вы знаете, что произошло что-то крайне неправильное. Конечно, вызов malloc внутри кода на ассемблере тоже довольно плохая вещь — вы, например, забыли проверить, вернул ли он NULL, так что вы вполне можете потерпеть крах. Помните, что за пределами вашего ассемблера — и проверьте NULL, гораздо проще отладить «Не удалось выделить память в строке 54 в файле mycode.c», чем «Где-то в ассемблере, мы получили

Вот несколько советов по улучшению, которые должны немного ускорить ваш цикл:

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
}
}

Улучшения: Убрать умножение на четыре в каждом цикле. Просто приращение esi вместо. Используйте декремент в ecx вместо инкремента и загрузите его членами до цикла. Это позволяет использовать только один прыжок в цикле, а не два. Удалить избыточный ход от edx к eax. Используйте eax напрямую.

0

Я разобрался с ответом самостоятельно.

Для тех, у кого была такая же или похожая проблема:

Фактическое исключение произошло после пользовательского кода, когда vc ++ автоматически выдвигает / восстанавливает регистры в их состояния до вызова функции. Так как я неправильно выравнивал указатель стека при вызове malloc, при извлечении из стека произошло нарушение доступа. Я не смог увидеть это в редакторе, потому что это был не мой код, поэтому он был показан как последний из моего кода в функции.

Чтобы исправить это, просто добавьте add 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
По вопросам рекламы [email protected]