#c #assembly #arm
#c #сборка #arm
Вопрос:
В моей попытке понять расположение памяти в процессе и изучить сборку я написал базовую программу на C на Pi3 (ARM) и разобрал ее с помощью GDB, но поскольку я новичок в этом, мне нужна помощь в ее понимании.
По сути, я пытаюсь понять и определить в сборке, где хранятся переменные (BSS, ДАННЫЕ, текстовые сегменты памяти), а также понимать и следовать фреймам стека.
Я отобразил только основную функцию — на экране отладки были и другие сегменты, поэтому дайте мне знать, если они тоже помогут!
Я понимаю, что по большей части делают отдельные инструкции, но что я хотел бы знать, так это:
- Первые 3 строки связаны с указателем стека — это настройка фрейма стека для основной функции?
- В x0x10414 используется значение для age, это где локальная переменная помещается в стек как часть фрейма для основной функции?
- В x0x1041c это возвращаемое значение, как я предполагал, тоже было помещено в стек как часть фрейма?
- Где стек сбрасывается в конце функции?
int main () {
int age = 30;
int salary;
return 0;
}
0x10408 <main> push {r11} ; (str r11, [sp, #-4]!)
x0x1040c <main 4> add r11, sp, #0
x0x10410 <main 8> sub sp, sp, #12
x0x10414 <main 12> mov r3, #30
x0x10418 <main 16> str r3, [r11, #-8]
x0x1041c <main 20> mov r3, #0
x0x10420 <main 24> mov r0, r3
x0x10424 <main 28> add sp, r11, #0
x0x10428 <main 32> pop {r11} ; (ldr r11, [sp], #4)
x0x1042c <main 36> bx lr
Комментарии:
1. Стек не «сбрасывается», это довольно распространенное заблуждение. Указатель стека восстанавливается до значения, которое он имел до вызова функции, значения, созданные в стеке функцией, считаются мусором и могут / будут перезаписаны при дальнейшем выполнении кода.
2. здесь используется указатель фрейма, поэтому указатель стека используется только для сохранения указателя фрейма. вызывающий предполагает, что указатель на фрейм останется таким, каким он был, когда они вызывали вас, поэтому мы должны сохранить его и восстановить. мы также должны сохранять и восстанавливать указатель стека до его исходного значения, но сам стек мы не делаем.
Ответ №1:
- Да, вы правы. Регистр
r11
используется в качестве указателя фрейма. Этот указатель фрейма служит ссылкой на то, где ваши локальные переменные хранятся в стеке. Обратите внимание, что исходный указатель на фрейм от вызывающего объекта должен быть сохранен (чтобы он был сохранен и восстановлен позже). - Почти. Это происходит на одну строку позже, оно сохраняет его в стеке по адресу [r11 — 8]. Помните, что
r11
это указатель на фрейм, все относительно этого. - Он не помещается в стек. Он просто возвращается в реестр
r0
. На многих платформах обычно используется регистр общего назначения. Тогда стек не нужно использовать для простых и простых возвращаемых значений (например, вашего целого числа). Я предполагаю, что это из соображений производительности, поскольку регистры быстрее, чем доступ к памяти. - Я не знаю, что вы имеете в виду под flushed. Здесь происходит то, что функция настраивает вещи так, как ей нравится, а затем отменяет эти изменения. Содержимое стека может по-прежнему содержать значения, которые использовала функция. Просто указатели сбрасываются в их исходные местоположения. Сначала в начале функции исходный указатель кадра (
r11
) сохраняется / помещается в стек. Затем значение указателя стека становится новым указателем фрейма. В конце функции указатель стека возвращается туда, где он был (путем перезаписи его сr11
помощью ), и, наконец, он такжеr11
восстанавливается, удаляя его из стека.