Объяснение, необходимое для этого ассемблерного кода

Это код c:

void test_function(int a, int b, int c, int d) 
{
int flag;
char buffer[10];
flag = 31337;
buffer[0] = 'A';
}
int main() 
{
test_function(1, 2, 3, 4);
}

Сборка test_function:

Dump of assembler code for function test_function:
0x08048344 <test_function+0>: push ebp
0x08048345 <test_function+1>: mov ebp,esp
0x08048347 <test_function+3>: sub esp,0x28
0x0804834a <test_function+6>: mov DWORD PTR [ebp-12],0x7a69
0x08048351 <test_function+13>: mov BYTE PTR [ebp-40],0x41
0x08048355 <test_function+17>: leave
0x08048356 <test_function+18>: ret

End of assembler dump.
(gdb) print $ebp-12
$1 = (void *) 0xbffff7dc
(gdb) print $ebp-40
$2 = (void *) 0xbffff7c0
(gdb) x/16xw $esp
0xbffff7c0: (1)0x00000000 0x08049548 0xbffff7d8 0x08048249
0xbffff7d0: 0xb7f9f729 0xb7fd6ff4 0xbffff808 0x080483b9
0xbffff7e0: 0xb7fd6ff4 (2)0xbffff89c (3)0xbffff808 (4)0x0804838b
0xbffff7f0: (5)0x00000001 0x00000002 0x00000003 0x00000004

Я новичок в этих темах; поэтому в голове есть некоторые вопросы.

  1. Я предполагаю, что первые 3 строки ассемблерного кода являются прологом. Он проталкивает ebp, затем копирует esp в ebt. Однако я не понял, почему esp возвращает память на 40 байт.
  2. Он помещает 31337 в ebp-12, но почему именно ebp-12 и представляет ли он память флага? Кажется, нет, так как внизу (2) обозначено как память флага.
  3. Ниже «x/16xw $esp», какие другие ячейки памяти не включают ни одного (числа) слева, поскольку ячейки памяти с числами представляют локальные переменные, параметры и sfp?

1) это 40 байт, а не бит. Это пространство, выделенное для локальных переменных. 2) Потому что компилятор решил разместить там flag. Непонятно, в какой момент вы остановили программу для создания дампа. 3) Я не понимаю вопроса, но это просто дамп памяти с адресами и значениями.

Jester 21.06.2023 21:17
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
77
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы проблема

It pushes ebp, then copies esp to ebt

ebt неверен, нет регистра, вызывающего ebt. Это должно быть ebp.

push ebp

команда предназначена для сохранения дна стека перед вызовом функции test_function.

mov ebp,esp
sub esp,0x28

команда предназначена для увеличения стека, чтобы выделить новый блок памяти для хранения значений во время выполнения функции test_function. А размер увеличения стека не фиксирован и не всегда будет 0x28. Это значение рассчитывается компилятором, который гарантирует, что размер подходит.

mov DWORD PTR [ebp-12],0x7a69

соответствует флагу = 31337, адрес флага равен значению ebp-12. Адрес назначается компилятором. DWORD соответствует int. Шестнадцатеричное число 0x7a69 эквивалентно десятичному числу 31337.

И

mov BYTE PTR [ebp-40],0x41

такой же как. Шестнадцатеричное число 0x41 эквивалентно десятичному числу 65. Десятичное значение кода ASCII для буквы A — это десятичное число 65. BYTE соответствует char.

Ниже код

(gdb) x/16xw $esp
0xbffff7c0: (1)0x00000000 0x08049548 0xbffff7d8 0x08048249
0xbffff7d0: 0xb7f9f729 0xb7fd6ff4 0xbffff808 0x080483b9
0xbffff7e0: 0xb7fd6ff4 (2)0xbffff89c (3)0xbffff808 (4)0x0804838b
0xbffff7f0: (5)0x00000001 0x00000002 0x00000003 0x00000004

Например, 0xbffff7c0: левый код — это адрес, его значение равно 0x00000000. Таким образом, значение адреса 0xbffff7c4(0xbffff7c4 = 0xbffff7c0 + 4) равно 0x08049548, потому что 0x00000000 занимает 4 байта. Значение адреса 0xbffff7c8 равно 0xbffff7d8. ....

Я думаю ниже код ассемблера

Dump of assembler code for function test_function:
0x08048344 <test_function+0>: push ebp
0x08048345 <test_function+1>: mov ebp,esp
0x08048347 <test_function+3>: sub esp,0x28
0x0804834a <test_function+6>: mov DWORD PTR [ebp-12],0x7a69
0x08048351 <test_function+13>: mov BYTE PTR [ebp-40],0x41
0x08048355 <test_function+17>: leave
0x08048356 <test_function+18>: ret

можно преобразовать приведенный ниже код (поскольку @Peter Cordes указывает, что «leave» равно «mov esp,ebp» + «pop ebp», см. https://www.felixcloutier.com/x86/leave)

Dump of assembler code for function test_function:
0x08048344 <test_function+0>: push ebp
0x08048345 <test_function+1>: mov ebp,esp
0x08048347 <test_function+3>: sub esp,0x28
0x0804834a <test_function+6>: mov DWORD PTR [ebp-12],0x7a69
0x08048351 <test_function+13>: mov BYTE PTR [ebp-40],0x41
                               mov esp,ebp   // here changed
                               pop ebp       // here changed
0x08048356 <test_function+18>: ret

Таким образом, мы можем получить изображение, см. ниже:

leave делает то же самое, что и mov ebp, esp / pop ebp (felixcloutier.com/x86/leave). GCC использует его, потому что это меньший машинный код. (На процессорах Intel это стоит еще одну операцию, но при оптимизации скорости большинство функций не будут использовать EBP в качестве указателя кадра.)
Peter Cordes 22.06.2023 04:02

@PeterCordes Спасибо за исправление. Я изменил свой ответ.

Whozcry 22.06.2023 04:11

Еще один вопрос. Разве esp не является указателем, как переход к памяти выделяет память по пути? Саб так делает или это специально для esp?

steatoda 22.06.2023 11:15

@steatoda Извините, мой родной язык не английский, поэтому, возможно, я неточно использовал слово «распределяет». esp - это указатель стека. Локальные переменные хранятся в стеке. Саб так делает или это специально для esp? Ответ под, смотрите картинку в моем ответе в последнем разделе.

Whozcry 22.06.2023 11:22

Другие вопросы по теме