Как адрес возврата указан в стеке? - PullRequest
7 голосов
/ 30 марта 2010

Это то, что я вижу, разбирая для утверждения function(1,2,3);:

movl   $0x3,0x8(%esp)
movl   $0x2,0x4(%esp)
movl   $0x1,(%esp)
call   0x4012d0 <_Z8functioniii>

Кажется, ret-адрес вообще не помещается в стек, тогда как работает ret?

Ответы [ 4 ]

6 голосов
/ 30 марта 2010

В процессоре x86 (как в примере с ассемблером) инструкция call помещает адрес возврата в стек и передает управление функции.

Не все процессорные архитектуры помещают адрес возврата в стек - часто существует набор из одного или нескольких регистров, предназначенных для хранения адресов возврата. На процессорах ARM инструкция BL помещает адрес возврата в определенный регистр (LR или «регистр связи») и передает управление функции. Процессор ia64 делает нечто подобное, за исключением того, что есть несколько возможных регистров (b0 - b7), которые могут получить адрес возврата, и один будет указан в инструкции (с b0 по умолчанию).

5 голосов
/ 30 марта 2010

В идеале, оператор call должен об этом позаботиться. Следующее местоположение счетчика программы будет помещено в стек. Когда вызванная функция (подпрограмма) завершает свою работу, и когда она сталкивается с оператором return, элемент управления теперь переходит к адресу, который был помещен в стек, и он выталкивается.

3 голосов
/ 30 марта 2010

Это зависит от ABI и архитектуры, но если адрес возврата попадает в стек, это побочный эффект инструкции call, которая помещает его туда.

1 голос
/ 05 июня 2014

вызов помещает текущее значение регистра RIP (адрес возврата) в стек + выполняет вызов
ret извлекает адрес возврата (который call нажат) с вершины стека (там есть регистры RSP) и записывает его в регистр RIP.

Пример для блока GNU / Linux: функция f вызывает функцию g и позволяет взглянуть на кадр g.

НИЗКИЙ АДРЕС

... <- RSP (указатель стека показывает вершину стека) регистрирует точки по этому адресу <br> местные г
Базовый указатель f (старое значение RBP) <- регистр RBP (базовый указатель) указывает на этот адрес <br> ret адрес f (старое значение RIP) (это то, что вызов (из f) выдвинул, и что ret (из g) выскочит)
аргументы, которые f вызвала g с и не вписались в регистры (я думаю, что в Windows это не так)
...

ВЫСОКИЙ АДРЕС

g освободит локальные переменные (movq% rsp,% rbp)
g выведет «старый RBP» и сохранит его в регистре RBP (pop% rbp)
g будет ret , который изменит RIP со значением, которое хранится там, где RSP указывает на

Надеюсь, это поможет

...