Это все о реестре BP / EBP / RBP на платформах Intel. По умолчанию в этом регистре используется сегмент стека (не требуется специальный префикс для доступа к сегменту стека).
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. Эти обстоятельства 32-битных и 64-битных платформ x86 по существу означают, что регистр EBP / RBP может использоваться без какого-либо префикса в инструкциях процессора, которые обращаются к памяти.
Таким образом, параметр компилятора, о котором вы писали, позволяет использовать BP / EBP / RBP для других целей, например, для хранения локальной переменной.
Под этим подразумевается избегание инструкций по сохранению, настройке и восстановлению указателей кадров, подразумевается избегание следующего кода при вводе каждой функции:
push ebp
mov ebp, esp
или инструкция enter
, которая была очень полезна на процессорах Intel 80286 и 80386.
Также перед возвратом функции используется следующий код:
mov esp, ebp
pop ebp
или инструкция leave
.
Инструменты отладки могут сканировать данные стека и использовать эти переданные данные регистров EBP при нахождении call sites
, то есть для отображения имен функции и аргументов в том порядке, в котором они были вызваны иерархически.
У программистов могут возникнуть вопросы о кадрах стека не в широком смысле (что это единый объект в стеке, который обслуживает только один вызов функции и сохраняет адрес возврата, аргументы и локальные переменные), а в узком смысле - когда упоминается термин stack frames
в контексте параметров компилятора. С точки зрения компилятора, кадр стека - это просто код входа и выхода для подпрограммы, который подталкивает якорь к стеку - который также можно использовать для отладки и для обработки исключений. Инструменты отладки могут сканировать данные стека и использовать эти якоря для обратной трассировки, находя call sites
в стеке, то есть отображать имена функций в том же порядке, в котором они были вызваны иерархически.
Вот почему программисту важно понимать, что такое стековый фрейм с точки зрения параметров компилятора - потому что компилятор может контролировать, генерировать этот код или нет.
В некоторых случаях кадр стека (код входа и выхода для процедуры) может быть опущен компилятором, а доступ к переменным будет осуществляться напрямую через указатель стека (SP / ESP / RSP), а не через удобный базовый указатель (BP / ESP / RSP). Условия, при которых компилятор пропускает кадры стека для некоторых функций, могут быть разными, например: (1) функция является листовой функцией (т. Е. Конечной сущностью, которая не вызывает другие функции); (2) не используются исключения; (3) никакие процедуры не вызываются с исходящими параметрами в стеке; (4) функция не имеет параметров.
Пропуск фреймов стека (код входа и выхода для процедуры) может сделать код меньше и быстрее. Тем не менее, они также могут отрицательно повлиять на способность отладчиков отслеживать данные стека и отображать их программисту. Это параметры компилятора, которые определяют, при каких условиях функция должна удовлетворять, чтобы компилятор присудил ей код входа и выхода из кадра стека. Например, у компилятора могут быть варианты добавления такого кода входа и выхода к функциям в следующих случаях: (а) всегда, (б) никогда, (в) при необходимости (с указанием условий).
Возвращаясь от общих к частностям: если вы используете параметр компилятора -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-pointer на машинах, где это не мешает отладке.
Поэтому неясно, из документации как таковой, будет ли -fomit-frame-pointer
включен, если вы просто компилируете с одним параметром `-O 'на платформе x86. Его можно проверить эмпирически, но в этом случае разработчики GCC не обязуются не изменять поведение этой опции в будущем без предварительного уведомления.
Однако Питер Кордес указал в комментариях, что есть разница в настройках по умолчанию -fomit-frame-pointer
между x86- 16 платформ и платформы x86-32 / 64.
Этот параметр - -fomit-frame-pointer
- также относится к Intel C ++ Compiler 15.0, а не только в GCC:
Для компилятора Intel у этого параметра есть псевдоним /Oy
.
Вот что об этом написала Intel:
Эти параметры определяют, используется ли EBP как универсальный регистр при оптимизации. Опции -fomit-frame-pointer и / Oy позволяют это использовать. Опции -fno-omit-frame-pointer и / Oy- запрещают это.
Некоторые отладчики ожидают, что EBP будет использоваться в качестве указателя кадра стека, и не могут производить обратную трассировку стека, если это не так. Параметры -fno-omit-frame-pointer и / Oy- предписывают компилятору сгенерировать код, который поддерживает и использует EBP в качестве указателя кадра стека для всех функций, чтобы отладчик мог по-прежнему производить обратную трассировку стека, не выполняя следующие действия:
Для -fno-omit-frame-pointer: отключение оптимизаций с помощью -O0. Для / Oy-: отключение / O1, / O2 или / O3 оптимизации. Параметр -fno-omit-frame-pointer устанавливается, когда вы указываете параметр - O0 или параметр -g. Параметр -fomit-frame-pointer устанавливается, когда вы указываете параметр -O1, -O2 или -O3.
Параметр / Oy устанавливается при указании параметра / O1, / O2 или / O3. Параметр / Oy- устанавливается при указании параметра / Od.
Использование параметра -fno-omit-frame-pointer или / Oy- уменьшает количество доступных регистров общего назначения на 1 и может привести к несколько менее эффективному коду.
ПРИМЕЧАНИЕ Для систем Linux *: в настоящее время существует проблема с обработкой исключений GCC 3.2. Поэтому компилятор Intel игнорирует этот параметр, если для C ++ установлен GCC 3.2 и включена обработка исключений (по умолчанию).
Имейте в виду, что приведенная выше цитата актуальна только для компилятора Intel C ++ 15, а не для GCC.
person
Maxim Masiutin
schedule
14.07.2017
Release
иDebug
на самом деле очень полезно, возьмите этот вариант в качестве примера. - person Kotauskas   schedule 12.05.2019Release
-build? - person Andreas Magnusson   schedule 30.04.2020