Подтвердить что ты не робот

Что такое рамка стека в сборке?

Какова структура фрейма стека и как он используется при вызове функций в сборке?

4b9b3361

Ответ 1

Кадр стека x86-32 создается путем выполнения

function_start:
    push ebp
    mov ebp, esp

поэтому он доступен через ebp и выглядит как

ebp+00 (current_frame) : prev_frame
ebp+04                 : return_address
                         ....
prev_frame             : prev_prev_frame
prev_frame+04          : prev_return_address

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

Ответ 2

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

Фрейм стека для каждой подпрограммы делится на три части: функциональные параметры, обратный указатель на предыдущий кадр стека и локальные переменные.

Часть 1: функциональные параметры

Эта часть стандартного фрейма стека настраивается вызывающим абонентом. Используя команду "push", вызывающий пользователь выталкивает параметры в стек. Различные языки могут подталкивать параметры в разных порядках. C, если я правильно помню, толкает их справа налево. То есть, если вы звоните...

foo (a, b, c);

Вызывающий преобразует это значение в...

push c
push b
push a
call foo

Когда каждый элемент помещается в стек, стек увеличивается. То есть регистр указателя стека уменьшается на четыре (4) байта (в 32-битном режиме), и элемент копируется в ячейку памяти, на которую указывает регистр стека. Обратите внимание, что команда "вызов" будет неявно нажать адрес возврата в стеке. Очистка параметров будет рассмотрена в части 5.

Часть 2: указатель обратной ссылки на стопку

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

[esp + 0]   - return address
[esp + 4]   - parameter 'a'
[esp + 8]   - parameter 'b'
[esp + 12]  - parameter 'c'

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

push ebp        ; save previous stackbase-pointer register
mov  ebp, esp   ; ebp = esp

Иногда вы можете увидеть это, используя только инструкцию 'ENTER'.

Часть 3: Резьба для локальных переменных

Локальные переменные сохраняются в стеке. Поскольку стек растет, мы вычитаем несколько байтов (достаточно для хранения наших локальных переменных):

sub esp, n_bytes ; n_bytes = number of bytes required for local variables

Часть 4: Объединим все это. Доступ к параметрам осуществляется с помощью регистра указателя стека...

[ebp + 16]  - parameter 'c'
[ebp + 12]  - parameter 'b'
[ebp + 8]   - parameter 'a'
[ebp + 4]   - return address
[ebp + 0]   - saved stackbase-pointer register

Доступ к локальным переменным осуществляется с помощью регистра указателя стека...

[esp + (# - 4)] - top of local variables section
[esp + 0]       - bottom of local variables section

Часть 5: Очистка стоп-кадров

Когда мы покидаем процедуру, стоп-фрейм должен быть очищен.

mov esp, ebp   ; undo the carving of space for the local variables
pop ebp        ; restore the previous stackbase-pointer register

Иногда вы можете увидеть инструкцию "LEAVE", заменяя эти две инструкции.

В зависимости от языка, который вы использовали, вы можете увидеть одну из двух форм инструкции "RET".

ret
ret <some #>

Какой бы выбор ни выбрали, будет зависеть от выбора языка (или стиля, который вы хотите использовать для написания на ассемблере). Первый случай указывает на то, что вызывающий отвечает за удаление параметров из стека (с примером foo (a, b, c) он будет делать это через... add esp, 12), и это способ "C" Это. Второй случай указывает, что команда return будет выталкивать # слова (или # байты, я не могу вспомнить, какой) из стека, когда он возвращается, тем самым удаляя параметры из стека. Если я правильно помню, это стиль, используемый Паскалем.

Это долго, но я надеюсь, что это поможет вам лучше понять стековые кадры.

Ответ 3

Это зависит от используемой операционной системы и языка. Причина в том, что в ASM нет общего формата для стека, единственное, что делает стек в ASM, - это сохранить обратный адрес при выполнении подпрограммы перехода. При выполнении функции return-from-sub адрес выбирается из стека и помещается в программу-счетчик (ячейка памяти, в которой должна быть записана следующая команда выполнения ЦП)

Вам потребуется проконсультироваться с вашей документацией для используемого компилятора.

Ответ 4

Кадр стека x86 может использоваться компиляторами (в зависимости от компилятора) для передачи параметров (или указателей на параметры) и возвращаемых значений. См. this