Инструкция CALL ВСЕГДА помещает адрес, указанный EIP, в стек?

Есть ли какое-либо условие, при котором адрес возврата не помещается в стек во время вызова функции в архитектуре x86?


person balajimc55    schedule 13.11.2015    source источник
comment
Если вы хотите выполнить вызов функции без доступа к стеку, вы можете (промахнуться) использовать инструкции syscall или sysenter.   -  person Martin Rosenau    schedule 13.11.2015
comment
Во время вызова функции: если вы избегаете самой инструкции call, вы можете выполнить хвостовой вызов с помощью jmp, который ничего не нажимает.   -  person Peter Cordes    schedule 14.04.2021


Ответы (1)


CALL по определению поместит адрес возврата в стек перед переходом к целевому адресу. Этот адрес возврата равен EIP (или RIP) + sizeof(call instruction) (обычно 5 байт).

В томе 2 Руководства разработчика программного обеспечения для архитектур Intel® 64 и IA-32 говорится, что CALL:

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

Это включает:

  • Near Call — «вызов процедуры в текущем сегменте кода», когда EIP помещается в стек.
  • Дальний вызов — «Вызов процедуры, расположенной в сегменте, отличном от текущего сегмента кода», где CS, EIP помещаются в стек.

Альтернативой, не отправляющей адрес возврата, является JMP.

Каждый компилятор C, с которым я знаком, всегда реализует вызовы функций на x86 с помощью инструкции CALL, за одним исключением: вызов хвоста , который можно реализовать с помощью файла JMP. Особенно это происходит, когда одна функция возвращает результат вызова другой функции. Например.

int bar(int a, int b);

int foo(int a, int b)
{
    if (a < b)
       return 0;

    return bar(a, b);   // Will probably be:    jmp  bar
}
person Jonathon Reinhart    schedule 13.11.2015
comment
Реализует ли какой-либо компилятор вызовы функций (в C) с использованием каких-либо средств, кроме инструкций CALL - RET в ассемблере (например, JMP)? - person balajimc55; 13.11.2015
comment
@ balajimc55 Если вызов функции помечен как встроенный и/или включен оптимизатор, в полученном ассемблерном коде может быть полностью удалена инструкция вызова, а тело функции (вызываемой) помещено прямо внутри функции, которая должна была назови это. - person Michael Petch; 13.11.2015
comment
@MichaelPetch Да, я знаю о встроенных вызовах. Я просто хотел узнать о случае, когда инструкция возврата не проталкивается в обычном вызове функции! Обновленный ответ Джонатона точно отвечает на мои сомнения! - person balajimc55; 13.11.2015
comment
Когда вызываемая цель находится за пределами сегмента, возникает исключение, и адрес возврата не передается. - person vitsoft; 13.11.2015
comment
@vitsoft Верное замечание, но я предполагал, что ОП имел в виду успешную передачу выполнения. - person Jonathon Reinhart; 13.11.2015