Что эквивалентно инструкции x86 "ret"?
Скажем, я пишу процедуру в сборке x86, например, "add", которая добавляет два числа, переданные в качестве аргументов.
По большей части это очень простой метод:
push ebp
mov ebp, esp
mov eax, [ebp+8]
add eax, [ebp+12]
mov esp, ebp
pop ebp
ret
Но, можно ли каким-либо образом переписать этот метод, чтобы избежать использования инструкции "ret" и все равно получить точный результат?
Ответы
Ответ 1
Для моделирования ret
не нужны никакие свободные регистры, но для этого требуется 4 байта памяти (dword). Использует косвенный jmp
. Изменить: Как отметил Ирак Бакстер, этот код не является повторным. Работает отлично в однопоточном коде. Сбой при использовании в многопоточном коде.
push ebp
mov ebp, esp
mov eax, [ebp+8]
add eax, [ebp+12]
mov ebp, [ebp+4]
mov [return_address], ebp
pop ebp
add esp,4
jmp [return_address]
.data
return_address dd 0
Заменить только инструкцию ret
, не изменяя остальную часть кода. Не реентерабельный. Не используйте в многопоточном коде. Изменить: исправлена ошибка ниже кода.
push ebp
mov ebp, esp
mov ebp, [ebp+4]
mov [return_address], ebp
pop ebp
add esp,4
jmp [return_address]
.data
return_address dd 0
Ответ 2
Конечно.
push ebp
mov ebp, esp
mov eax, [ebp+8]
add eax, [ebp+12]
mov esp, ebp
pop ebp
pop ecx ; these two instructions simulate "ret"
jmp ecx
Это предполагает, что у вас есть свободный регистр (например, ecx). Написание эквивалента, который использует "без регистров", возможно (ведь x86 является машиной Тьюринга), но, вероятно, будет включать множество свернутых регистров и перетасовку стека.
Большинство современных ОС предлагают хранилище, специфичное для потоков, доступное одному из регистров сегментов. Вы могли бы затем имитировать "ret" таким образом, безопасно:
pop gs:preallocated_tls_slot ; pick one
jmp gs:preallocated_tls_slot
Ответ 3
Не тестировались, но вы можете сделать ret, не используя GPR:
add esp,4
jmp dword ptr [esp-4]
Ответ 4
push ebp
mov ebp, esp
mov ebp, [ebp+4]
mov [return_address], ebp
nop
pop ebp
add esp,4
iret
jmp [return_address]
.data
return_address dd 0
Инструкция nop отклонит процесс 8080 и пропустит mov, ebp, если значение недействительно или выполнимо, и выполнение следующей допустимой команды-добавления esp, 4 и jmp [return_address]. Также предотвращает утечку Killer.EXE его когти в виде Killer.EXE убивают плохие 8 и 16-битные операции. В VCPI это может быть очень неприятной ошибкой для debug.Also iret установит отдачу от точки после добавления esp, 4.
Это необязательно, но во всех действиях для отладки - и это то, что вы делаете, вы смотрите на инструкцию, для которой не используются 8-битные мнемоники и вы хотите их исключить - поскольку вы устанавливаете это в своем первом сегменте кода push ebp, который базовый указатель.Если ошибка является ebp, то 8-битные регистры устанавливают команду nop под push ebp [base pointer], к которой недействителен, толкает esp в ebp и удаляет второй mov ebp, esp и вводит iiret туда, где эта строка существовала.
Это два жизнеспособных варианта - но я всего лишь ассемблер FLAT, и что я знаю о режимах, которые превышают двумерный формат. Я просто сказал вам, что вы должны выполнить отладку gui gpf, которая является плоской модель 32-разрядной инструкции.