Я новичок на языке ассемблера и заметил, что код x86, испускаемый компиляторами, обычно поддерживает указатель на фреймворк даже в режиме release/оптимизации, когда он может использовать регистр EBP для чего-то другого. Я понимаю, почему указатель кадра может сделать код более легким для отладки и может потребоваться, если alloca() вызывается внутри функции. Тем не менее, x86 имеет очень мало регистров, и использование двух из них для хранения местоположения фрейма стека, когда этого достаточно, просто не имеет смысла для меня. Почему опускание указателя рамки считается плохим даже в оптимизированных/выпусках?
Какова цель регистра указателя кадров EBP?
Ответ 1
Указатель кадра - это ссылочный указатель, позволяющий отладчику знать, где находится локальная переменная или аргумент с одним постоянным смещением. Несмотря на то, что значение ESP изменяется в ходе выполнения, EBP остается тем же самым, позволяя достичь той же переменной с тем же самым смещением (такой как первый параметр всегда будет на EBP + 8, а смещения ESP могут значительно измениться, так как вы будете толкать /popping )
Почему компиляторы не выбрасывают указатель рамки? Поскольку с помощью указателя кадра отладчик может определить, где локальные переменные и аргументы используют таблицу символов, так как они гарантированно будут иметь постоянное смещение к EBP. В противном случае нет простого способа определить, где локальная переменная находится в любой точке кода.
Как упоминал Грег, он также помогает раскручивать стек для отладчика, поскольку EBP предоставляет обратный связанный список стековых кадров, что позволяет отладчику определить размер фрейма стека (локальные переменные + аргументы) функции.
Большинство компиляторов предоставляют возможность пропускать указатели на фреймы, хотя это делает отладки очень тяжело. Этот вариант никогда не должен использоваться глобально, даже в коде выпуска. Вы не знаете, когда вам нужно будет отладить сбой пользователя.
Ответ 2
Просто добавив мои два цента к уже хорошим ответам.
Это часть хорошей языковой архитектуры, чтобы иметь цепочку кадров стека. BP указывает на текущий кадр, где хранятся локальные переменные подпрограммы. (Локали находятся в отрицательных смещениях, а аргументы находятся в положительных смещениях.)
Идея о том, что он предотвращает использование превосходного регистра в оптимизации, ставит вопрос: когда и где оптимизация действительно стоит?
Оптимизация стоит только в тесных циклах, которые 1) не вызывают функции, 2) где счетчик программ тратит значительную часть своего времени, и 3) в коде, который когда-либо видел компилятор (т.е. не-библиотечные функции), Обычно это очень малая часть общего кода, особенно в больших системах.
Другой код можно скрутить и сжать, чтобы избавиться от циклов, и это просто не имеет значения, потому что счетчик программ практически не существует.
Я знаю, что вы этого не спрашивали, но, по моему опыту, 99% проблем с производительностью не имеют ничего общего с оптимизацией компилятора. Они имеют все, что связано с чрезмерным дизайном.
Ответ 3
Это зависит от компилятора, конечно. Я видел оптимизированный код, испускаемый компиляторами x86, который свободно использует регистр EBP как регистр общего назначения. (Я не помню, какой компилятор я заметил с этим.)
Компиляторы также могут поддерживать ведение регистра EBP, чтобы помочь раскручивать стек во время обработки исключений, но опять же это зависит от точной реализации компилятора.
Ответ 4
Однако x86 имеет очень мало регистров
Это верно только в том смысле, что коды операций могут адресовать только 8 регистров. У самого процессора на самом деле будет гораздо больше регистров, чем это, и использовать переименование регистров, конвейерную обработку, спекулятивное выполнение и другие ключевые слова процессора, чтобы обойти этот предел. В Википедии есть хороший вводный параграф о том, что может сделать процессор x86 для преодоления предела регистра: http://en.wikipedia.org/wiki/X86#Current_implementations.
Ответ 5
Использование фреймов стека стало невероятно дешевым на любом оборудовании, даже отдаленно современным. Если у вас дешевые стоп-кадры, сохранение нескольких регистров не так важно. Я уверен, что быстрые фреймы стека против большего количества регистров были инженерным компромиссом, и выиграли быстрые стоп-фреймы.
Сколько стоит сохранение чистого реестра? Стоит ли это?