как работают вызовы процедур в assembler?
Я только начал возиться с ASM, и я не уверен, правильно ли мое понимание вызовов процедур.
говорят, в какой-то момент в коде есть вызов процедуры
call dword ptr[123]
и процедура состоит только из одной команды, ret:
ret 0004
каков будет эффект этого вызова процедуры и где будет храниться возвращаемое значение? Я где-то читал, что возвращаемое значение 2 байта будет храниться в AX, но когда я заменяю вызов процедуры by
mov AX, 0004
(вместе с необходимыми NOPs) программа аварийно завершает работу.
4 ответов
в ассемблере x86 параметр для ret
инструкция означает:
RET immediate
вернуться к процедуре вызова и pop немедленно байт из стека.
(цитата из руководства разработчика программного обеспечения Intel® 64 и IA-32 Architectures Vol 2B)
поэтому, когда вы печатаете:
ret 0004
вы говорите CPU вернуться к инструкции сразу после the call
, и вытащить 4 байта из стека. Это здорово, если вы толкнул 4 байта в стек перед вызовом.
push eax
call dword ptr[123]
обратите внимание, что это не имеет ничего общего с возвращенным значением. Фактически, процедура в сборке не может указать, что значение является возвращение значение. Все это делается по правилам. Большинство компиляторов, о которых я знаю, будут использовать EAX
для хранения возвращаемого значения, но это верно только потому, что вызов функция будет ожидать, что результат есть.
таким образом, ваш код вызова будет:
call dword ptr [123]
mov dword ptr [result], eax
и ваша функция, которая возвращает значение 4 будет:
mov eax, 4
ret
все зависит от соглашение о вызове используется. Я не буду повторять статью Википедии здесь, просто прочитайте определение.
на C вызов конвенции, например, возвращаемое значение будет в EAX/AX / AL. Ваша одиночная инструкция не имеет одного: это функция void, принимающая около 4 байтов параметров (возможно, один int), которая ничего не делает. Поскольку это обязанность вызываемого абонента очистить стек в этом соглашении о вызовах, игнорируя это это и замена вызова "mov ax" не работает.
также я подозреваю, что вы можете возиться с 32-битной сборкой при чтении 16-битного документа. Это не большая проблема, но вы должны знать о различиях.
// possibly there are arguments pushed here
...
call dword ptr[123] // push next OP code offset in the stack and jump to procedure
// procedure
...
ret 0004 // pop offset, set EIP to that offset and decrease ESP by 4
мы дополнительно уменьшите ESP, если мы перед вызовом процедуры вставили аргументы в стек.
Если есть выдвинуты аргументы, ваша программа аварийно завершает работу, потому что вы их не поп. Возвращаемое смещение для текущей процедуры будет неправильным, так как оно получит значение из одного из переданных аргументов в качестве смещения.