как вызовы процедур работают в ассемблере? - PullRequest
8 голосов
/ 09 августа 2009

Я только начал возиться с ASM и не уверен, правильно ли я понимаю вызовы процедур.

скажем, в какой-то момент в коде есть вызов процедуры

call dword ptr[123]

и процедура состоит только из одной команды, ret:

ret 0004

Каков будет эффект этого вызова процедуры и где будет храниться возвращаемое значение? Я где-то читал, что возвращаемое значение 2 байта будет храниться в AX, но когда я заменяю вызов процедуры на

mov AX, 0004

(вместе с необходимыми NOP) программа вылетает.

Ответы [ 4 ]

12 голосов
/ 09 августа 2009

в ассемблере x86 параметр для инструкции ret означает:

RET <i>immediate</i>

Возврат к вызывающей процедуре и извлечение немедленных байтов из стека.

(цитата из Руководства разработчика программного обеспечения для архитектуры Intel® 64 и IA-32 Том 2B )

Поэтому, когда вы печатаете:

ret 0004

Вы говорите ЦПУ вернуться к инструкции сразу после call и вытолкнуть 4 байта из стека. Это замечательно, если вы поместили 4 байта в стек перед вызовом.

push eax
call dword ptr[123]

Обратите внимание, что это не имеет ничего общего с возвращаемым значением. Фактически, процедура в Assembly не может указать, что значение является значением return . Это все сделано по соглашению. Большинство известных мне компиляторов будут использовать EAX для хранения возвращаемого значения, но это верно только потому, что функция , вызывающая , будет ожидать результата там.

Таким образом, ваш телефонный код будет:

call dword ptr [123]
mov dword ptr [result], eax

и ваша функция, которая возвращает значение 4, будет:

mov eax, 4
ret
2 голосов
/ 09 августа 2009

Все зависит от используемого соглашения о вызовах . Я не буду повторять статью из Википедии здесь, просто прочитайте определение.

Например, в соглашении о вызовах C возвращаемое значение будет в EAX / AX / AL. Ваша одиночная инструкция не имеет таковой: это пустая функция, принимающая около 4 байтов параметров (возможно, один int), которая ничего не делает. Поскольку в этом соглашении о вызовах обязан вызываемый объект очистить стек, игнорирование этого и замена вызова на «mov ax» не работает.

Также я подозреваю, что вы можете возиться с 32-битной сборкой при чтении 16-битного документа. Это не большая проблема, но вы должны знать о различиях.

1 голос
/ 09 августа 2009
// 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, если перед вызовом процедуры мы поместили аргументы в стек.


Если есть выдвинутые аргументы, ваша программа падает, потому что вы их не выталкиваете. Смещение возврата для текущей процедуры будет неправильным, поскольку в качестве смещения будет получено значение из одного из выдвинутых аргументов.

0 голосов
/ 09 августа 2009

Я не думаю, что возвращаемое значение сохраняется в регистре AX

...