Попытка понять опцию gcc-fomit-frame-pointer
Я попросил Google дать мне значение gcc опции -fomit-frame-pointer, который перенаправляет меня на следующий оператор.
- fomit-frame-pointer
Не держите указатель кадра в регистре для функций, которые в нем не нуждаются. Это позволяет избежать инструкций по сохранению, настройке и восстановлению указателей кадров; это также делает дополнительный регистр доступным во многих функциях. Это также делает отладку невозможной на некоторых машины.
согласно моим знаниям о каждой функции, запись активации будет создана в стеке памяти процесса, чтобы сохранить все локальные переменные и некоторую дополнительную информацию. Я надеюсь, что этот указатель кадра означает, что адрес записи активации функции.
в этом случае, каковы типы функций, для которых не нужно хранить указатель кадра в регистре? Если я получу эту информацию, я постараюсь разработать новую функцию на основе этого (если это возможно), потому что если указатель кадра не хранится в регистрах, некоторые инструкции будут опущены в двоичном. Это действительно значительно улучшит производительность в приложении, где есть много функций.
2 ответов:
большинство меньших функций не нуждаются в указателе кадра - большие функции могут нуждаться в нем.
это действительно о том, насколько хорошо компилятор удается отслеживать, как используется стек, и где вещи находятся в стеке (локальные переменные, аргументы, переданные текущей функции и аргументы, подготовленные для функции, которая будет вызвана). Я не думаю, что легко охарактеризовать функции, которые нуждаются или не нуждаются в указателе кадра (технически, ни одна функция не должна иметь указатель кадра - это скорее случай "если компилятор считает необходимым уменьшить сложность другого кода").
Я не думаю, что вы должны "пытаться сделать функции без указателя кадра" как часть вашей стратегии кодирования - как я уже сказал, простые функции не нуждаются в них, поэтому используйте
-fomit-frame-pointer, и вы получите еще один регистр, доступный для распределителя регистров, и сохраните 1-3 инструкции по входу/выходу в функции. Если ваша функция нуждается в указателе фрейма, это потому, что компилятор решает это лучший вариант, чем не использовать указатель кадра. Это не цель иметь функции без указателя кадра, это цель иметь код, который работает правильно и быстро.обратите внимание, что "отсутствие указателя кадра" должно дать лучшую производительность, но это не какая - то волшебная пуля, которая дает огромные улучшения-особенно не на x86-64, у которого уже есть 16 регистров для начала. На 32-битном x86, так как он имеет только 8 регистров, один из которых является указателем стека, и занимает другой в качестве указателя кадра означает, что 25% регистра-пространства занято. Чтобы изменить это на 12,5%, это довольно улучшение. Конечно, компиляция для 64-битных тоже очень поможет.
это все о регистре BP/EBP/RBP на платформах Intel. Этот регистр по умолчанию имеет значение stack segment (не требует специального префикса для доступа к Stack segment).
EBP-это лучший выбор регистра для доступа к структурам данных, переменным и динамически выделенному рабочему пространству в стеке. EBP часто используется для доступа к элементам в стеке относительно фиксированной точки в стеке, а не относительно текущего TOS. Это, как правило, определяет базовый адрес текущего кадра стека, установленного для текущей процедуры. Когда EBP используется в качестве Базового регистра при расчете смещения, смещение вычисляется автоматически в текущем сегменте стека (т. е. сегменте, выбранном в данный момент SS). Поскольку SS не нужно указывать явно, кодирование команд в таких случаях более эффективно. EBP также может использоваться для индексирования в сегменты, адресуемые через другие сегментные регистры.
( источник - http://css.csail.mit.edu/6.858/2017/readings/i386/s02_03.htm )
поскольку на большинстве 32-разрядных платформ сегмент данных и сегмент стека одинаковы, эта ассоциация EBP/RBP со стеком больше не является проблемой. Так же и на 64-битных платформах: архитектура x86-64, представленная AMD в 2003 году, в значительной степени снизила поддержку сегментации в 64-битном режиме: четыре регистра сегмента: CS, SS, DS и ES вынуждены равняться 0. Эти обстоятельства x86 32-разрядные и 64-разрядные платформы по существу означают, что регистр EBP/RBP может использоваться без какого-либо префикса в инструкциях процессора, которые обращаются к памяти.
таким образом, параметр компилятора, о котором вы писали, позволяет использовать BP/EBP/RBP для других средств, например для хранения локальной переменной.
под "это позволяет избежать инструкций по сохранению, настройке и восстановлению указателей кадров" подразумевается избегание следующего кода при вводе каждой функции:
push ebp mov ebp, espили
enterинструкция, которая был очень полезен на процессорах Intel 80286 и 80386.кроме того, перед возвращением функции используется следующий код:
mov esp, ebp pop ebpили
leaveинструкция.отладочные инструменты могут сканировать данные стека и использовать эти данные толкаемого регистра EBP при поиске
call sites, т. е. для отображения имен функции и аргументов в порядке их иерархического вызова.у программистов могут возникнуть вопросы о кадрах стека не в a широкий термин (что это одна сущность в стеке, которая обслуживает только один вызов функции и сохраняет обратный адрес, Аргументы и локальные переменные), но в узком смысле – когда термин
stack framesупоминается в контексте параметров компилятора. С точки зрения компилятора, кадр стека-это просто код входа и выхода для процедуры, что толкает якорь в стек – это также может быть использован для отладки и обработки исключений. Средства отладки могут сканировать данные стека и используйте эти якоря для обратной трассировки, при поискеcall sitesв стеке, т. е. для отображения имен функций в том порядке, в котором они были вызваны иерархически.вот почему очень важно понять программисту, что такое стек, с точки зрения компилятора – потому что компилятор может контролировать, Создавать ли этот код или нет.
в некоторых случаях фрейм стека (код входа и выхода для подпрограммы) может быть опущен компилятором, и переменные будут напрямую доступны через указатель стека (SP/ESP/RSP), а не удобный базовый указатель (BP/ESP/RSP). Условия, при которых компилятор пропускает кадры стека для некоторых функций, могут быть различными, например: (1) функция является конечной функцией (т. е. конечной сущностью, которая не вызывает другие функции); (2) не используются исключения; (3) не вызываются подпрограммы с исходящими параметрами в стеке; (4) функция не имеет параметров.
пропуск кадров стека (запись и код выхода для подпрограммы) может сделать код меньше и быстрее, но также может негативно повлиять на способность отладчиков отслеживать данные в стеке и отображать их программисту. Это параметры компилятора, которые определяют, при каких условиях функция должна удовлетворять, чтобы компилятор назначил ей код входа и выхода кадра стека. Например, компилятор может иметь опции для добавления такого кода входа и выхода в функции в следующих случаях: (a) всегда, (b) никогда, c) при необходимости (с указанием условий).
возвращаясь от общего к частностям: если вы будете использовать
-fomit-frame-pointerопция компилятора GCC, вы можете выиграть как при вводе, так и при выходе кода для подпрограммы, а также при наличии дополнительного регистра (если он уже не включен по умолчанию либо сам, либо неявно другими параметрами, в этом случае вы уже получаете выгоду от использования регистра EBP/RBP, и никакой дополнительный выигрыш не будет получен явно указание этого параметра, если он уже включен неявно). Однако обратите внимание, что в 16-битных и 32-битных режимах регистр BP не имеет возможности доступа к 8-битным частям, таким как AX (AL и AH).поскольку эта опция, помимо того, что позволяет компилятору использовать EBP в качестве универсального регистра в оптимизациях, также предотвращает генерацию кода выхода и входа для кадра стека, что усложняет отладку - вот почему документация GCC явно состояния (необычайно подчеркнутые жирным шрифтом), которые включают эту опцию делает отладку невозможной на некоторых машинах
также имейте в виду, что другие параметры компилятора, связанные с отладкой или оптимизацией, могут неявно включать
-fomit-frame-pointerопция вкл или выкл.я не нашел никакой официальной информации по адресу gcc.gnu.org о том, как другие параметры влияют
-fomit-frame-pointerна платформах x86, этот https://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Optimize-Options.html только утверждает следующее:- O также включает-fomit-frame-указатель на машинах, где это не мешает отладке.
так что непонятно из документации как таковой ли
-fomit-frame-pointerбудет включен, если вы просто скомпилировать с одного-Oопция на платформе x86. Это может быть проверено эмпирически, но в этом случае есть никаких обязательств от разработчиков GCC не изменять поведение этой опции в будущем без предварительного уведомления.однако, Питер Кордес указал в комментарии, что есть разница для настроек по умолчанию
-fomit-frame-pointerмежду платформами x86-16 и x86-32/64.этот вариант --
-fomit-frame-pointer-- тоже относится к компилятору Intel C++ 15.0, не только в GCC:для компилятора Intel, это опция имеет псевдоним
/Oy.вот что Intel написала об этом:
эти параметры определяют, используется ли EBP в качестве регистра общего назначения при оптимизации. Опции-fomit-frame-pointer и /Oy позволяют это использовать. Параметры-fno-опустить-кадр-указатель и /Oy-запретить его.
некоторые отладчики ожидают, что EBP будет использоваться в качестве указателя кадра стека и не может создать обратную трассировку стека, если это не так. The-fno-omit-frame-pointer and /Oy- параметры направляют компилятор на создание кода, который поддерживает и использует EBP в качестве указателя кадра стека для всех функций, чтобы отладчик все еще мог создавать обратную трассировку стека без выполнения следующих действий:
For-fno-omit-frame-pointer: отключение оптимизации с помощью-O0 Для /Oy-: отключение /O1, /O2 или / O3 оптимизации Интернет -ФНО-опустить-рамка-указатель параметр имеет значение при задании опции -О0 или параметром-G. Параметр-fomit-frame-pointer устанавливается при указании параметра - O1,- O2, или-O3.
параметр /Oy устанавливается при указании параметров /O1, /O2 или /O3. Параметр / Oy-устанавливается при указании параметра / Od.
использование параметра-fno-omit-frame-pointer или /Oy - уменьшает количество доступных регистров общего назначения на 1 и может привести к несколько менее эффективному коду.
примечание для систем Linux*: в настоящее время существует проблема с обработкой исключений GCC 3.2. Таким образом, компилятор Intel игнорирует это опция, когда GCC 3.2 установлен для C++ и обработка исключений включена (по умолчанию).
обратите внимание, что приведенная выше цитата относится только к компилятору Intel C++ 15, а не к GCC.
Comments