Различные способы выделения памяти для стека в gcc

Как gcc определяет, сколько памяти выделяется для стека и почему он больше не уменьшает% rsp, когда я удаляю printf() (или любой вызов функции) из основного?

1. Я заметил, когда поигрался с образцом кода: https://godbolt.org/z/fQqkNE, что 6th line в программе просмотра сборок gcc subq $48, %rsp удаляется, если я удалю printf() из своего C кода на line 22. Похоже, что когда я не делаю никаких вызовов функций из своей main, тогда %rsp не уменьшается, но данные по-прежнему распределяются на основе %rbp и смещений. Думал %rsp меняется только при росте стека. Моя теория состоит в том, что, поскольку он не будет вызывать никаких других функций, он знает, что ему не нужно хранить стек для других несуществующих функций. Но разве не должно %rsp расти по мере сохранения данных?

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

3. Есть ли онлайн-инструмент, который будет принимать ассемблерный код в качестве входных данных, а затем рисовать изображение стека и сообщать мне состояние каждого регистра в любой момент выполнения? Godbolt.org — очень хороший инструмент, я бы просто хотел, чтобы у него были эти две дополнительные функции.

Я вставлю приведенный ниже код на случай, если в будущем ссылка на Godbolt перестанет работать:

#include <stdio.h> #include <stdint.h> struct rect { int a; int b; int* c; int d[2]; uint8_t f; }; int main() { int arr[2] = {2, 3}; struct rect Rect; Rect.a = 10; Rect.b = 20; Rect.c = arr; Rect.d[0] = Rect.a; Rect.d[1] = Rect.b; Rect.f =255; printf(«%d and %d», Rect.a, Rect.b); return 0; } .LC0: .string «%d and %d» main: pushq %rbp movq %rsp, %rbp subq $48, %rsp movl $2, -8(%rbp) movl $3, -4(%rbp) movl $10, -48(%rbp) movl $20, -44(%rbp) leaq -8(%rbp), %rax movq %rax, -40(%rbp) movl -48(%rbp), %eax movl %eax, -32(%rbp) movl -44(%rbp), %eax movl %eax, -28(%rbp) movb $-1, -24(%rbp) movl -44(%rbp), %edx movl -48(%rbp), %eax movl %eax, %esi movl $.LC0, %edi movl $0, %eax call printf movl $0, %eax leave ret

P.S .: В книге, за которой я следую, используется синтаксис AT&T для обучения x86. Это странно, потому что это значительно усложняет поиск онлайн-руководств.

x86-64 System V имеет красную зону на 128 байтов ниже RSP, на которую не будут асинхронно наступать обработчики сигналов или что-то еще. GCC может использовать это для локальных пользователей, если он не собирается сам вызывать какие-либо функции (что будет синхронно использовать пространство под RSP). См. Почему компилятор резервирует небольшой объем стека, но не весь размер массива?   —  person miran80    schedule 08.04.2020

2. GCC любит выравнивать стек по 16 и должен делать это перед вызовом функции. (Таким образом, он знает, что стек был выровнен на 16 перед call на main.) Кроме того, вы скомпилировали с отключенной оптимизацией, и даже с оптимизацией можно легко потратить впустую пространство.   —  person miran80    schedule 08.04.2020

3. Мне не известны какие-либо инструменты визуализации. Однако вы можете скомпилировать с -fverbose-asm, чтобы GCC аннотировал каждую инструкцию C-именами операндов. Он довольно хорошо работает в режиме отладки безумие (по умолчанию -O0); с включенной оптимизацией переменные C обычно заменяются изобретенными временными.   —  person miran80    schedule 08.04.2020

Источник: ledsshop.ru

Стиль жизни - Здоровье!