RSP не двигается при входе в новую функцию
При входе в функцию C я ожидал увидеть в разборке, как указатель стека вычитается достаточно, чтобы освободить место для переменных, но нет; Я только вижу, как адрес переменных напрямую доступен через ebp, когда esp все еще указывает на ebp.
push %rbp
mov %rsp,%rbp
movl $0x4,-0x4(%rbp)
mov $0x0,%eax
pop %rbp
retq
Мне пришлось создать много переменных и инициализировать их, чтобы компьютер воспринял их серьезно и посмотреть, как много свободного места было создано. Была ли разница действительно в количестве используемого пространства или в чем-то еще? и если да, то как освободить место, перемещая rsp, нужно только тогда, когда я запрашиваю много места?
1 ответ
ABI System V x86-64 имеет 128-байтную красную зону ниже RSP, которая защищена от асинхронного дублирования, то есть "принадлежит" функции.
Похоже, вы собрали int foo{ int x = 4; return 0; }
с gcc -O0
(оптимизации отключены), и gcc решил сохранить x
в красной зоне вместо регулировки rsp
"зарезервировать" / "выделить" пространство стека. (См. Вики-тег red-zone для получения дополнительной ссылки / информации.)
В этом весь смысл красной зоны: спасти тех, sub
/ add
инструкции в листовых функциях.
Кстати, просмотр неоптимизированного кода - это обычно пустая трата времени. -O1
по крайней мере, более читабельным, и -O2
/ -O3
имеют отношение к коду, который вам действительно нужен. См. Также Как удалить "шум" из выходных данных сборки GCC/clang?,
В программах без обработчиков сигналов вся область стека может эффективно использоваться как красная зона. пример: код-гольф с повышенной точностью Фибоначчи, использующий esp
в качестве указателя массива, потому что pop
это быстро и компактно. (AFAIK, обработчики сигналов - это единственное, что асинхронно сокращает память ниже rsp
). Красная зона позволяет компиляторам использовать ее без необходимости специальной опции компиляции (и такой опции нет для 32-битного режима, где SysV ABI не определяет красную зону). Доказательство отсутствия обработчиков сигналов, вероятно, невозможно даже при оптимизации всей программы.
Я только вижу, как адрес переменных напрямую доступен через ebp
Нет, ты не Доступ через ebp
В 64-битном коде произойдет сбой, поскольку стек находится за пределами 4 ГБ адресного пространства (по крайней мере, в Linux по умолчанию). Указатели являются 64-битными, поэтому gcc использует rbp
чтобы получить к ним доступ.
Использование префикса размера адреса для кодирования movl $0x4,-0x4(%ebp)
в 64-битном режиме было бы напрасной тратой размера кода, даже если бы это не было ошибкой.
Интересный факт: в x32 ABI (ILP32 в длинном режиме), где указатели являются 32-разрядными, gcc часто использует префикс размера адреса вместо дополнительных инструкций, чтобы обрезать возможный большой мусор в регистрах и убедиться, что режимы адресации оборачиваются в 2^32 вместо выходить за пределы 4ГБ (например, со смещением со знаком). Вместо того, чтобы делать это оптимально, по умолчанию он просто тупо использует префиксы размера адреса для каждой инструкции с явным операндом памяти. Но недавний патч заставляет его всегда использовать 64-битный rsp
вместо использования префиксов размера адреса даже для esp
,