Как вы правильно заметили, если эта подпрограмма вызывается с call
, то [ebp+4]
является адресом возврата. Это не значит, что это плохая идея.
Предположим, что процедура вызывается с call
. В этот момент «адрес возврата», который помещается в стек, является адресом байта, который следует сразу за кодом операции call
. Давайте назовем этот адрес x . Затем процедура извлекает из адреса x два 32-битных слова, одно по адресу x и одно по адресу x + 4 . Вычитает второе слово из первого, сохраняя результат в eax
. Наконец, процедура сохраняет обратно значение x + 8 в слоте стека [ebp+4]
, чистый эффект состоит в том, что при достижении ret
выполнение возобновляется по адресу x + 8 . С этой гипотезой подпрограмма выглядит как способ вычитать целые числа, которые находятся в середине кода, что-то вроде этого:
call yourroutine
dd 56478634
dd 18943675
mov ebx, eax ; an example instruction
Здесь call
возвращается к инструкции mov
, и в этот момент eax
содержит значение 37534959 (это 18943675, вычтенное из 56478634).
Как подпрограмма кода, она не очень полезна, поскольку это сложный способ загрузки eax
с постоянным значением, которое жестко закодировано (кодовое пространство обычно доступно только для чтения во время выполнения). Можно подумать, что такая подпрограмма может появиться как часть поддержки динамического связывания во время выполнения в некоторой архитектуре (динамическое связывание является проблематичным предметом).
Теперь давайте предположим, что вместо этого подпрограмма вызывается с jmp
. [ebp+4]
теперь обозначает все, что было на вершине стека в этой точке. Процедура принимает это значение (назовем его y ), получает два слова по адресам y и y + 4 , вычисляет результат вычитания в eax
и затем сохраняет y + 8 обратно в слот [ebp+4]
. Наконец, ret
интерпретирует этот слот как адрес возврата, то есть адрес некоторого кода, к которому должно перейти выполнение. Неважно, что при создании этого адреса не был задействован call
код операции; ret
все равно прыгнет к нему. На этот раз код вызова может выглядеть следующим образом:
push foobar
jmp yourroutine
... ; unreached code
foobar:
dd 56478634
dd 18943675
mov ebx, eax ; an example instruction
На этот раз это выглядит как параметризованный скачок с некоторой присущей ему нагрузкой eax
. Подобный код может существовать в реализации некоторых интерпретаторов для многопоточного кода . Однако, как домашнее задание, я совершенно уверен, что это не то, что было задумано (многопоточные интерпретаторы кода даже более привлекательны, чем динамические ссылки).