Почему GCC использует указатель кадра, когда я вызываю функции Win32 с аргументами?

Когда я компилирую 32-битный код C с GCC и опцией -fomit-frame-pointer, указатель кадра (ebp) не используется, если моя функция не вызывает функции Windows API с помощью stdcall и по крайней мере один параметр.

Например, если я использую только GetCommandLine() из Windows API, у которого нет параметров / аргументов, GCC пропустит указатель кадра и будет использовать ebp для других целей, ускоряя код и не имея этого бесполезного пролога.

Но в тот момент, когда я вызываю функцию Win32 stdcall, которая принимает хотя бы один аргумент, GCC полностью игнорирует указатель -fomit-frame и в любом случае использует указатель кадра, а код становится хуже при проверке, поскольку он не может использовать ebp для общего назначения вещи. Не говоря уже о том, что я нахожу указатель кадра совершенно бессмысленным. Я имею в виду, я хочу скомпилировать для выпуска и распространения, почему я должен заботиться об отладке? (если я хочу отладить, я просто использую отладочную сборку после воспроизведения ошибки)

Мой стек наверняка НЕ ​​содержит динамическое распределение, такое как alloca. Итак, стек имеет определенную структуру, но GCC выбирает тупой метод, несмотря на мои параметры? Я что-то упускаю, чтобы заставить его не использовать указатель кадра?

Второе мое преимущество в том, что он отказывается использовать "push" инструкции для функций Win32. Любой другой компилятор, который я пробовал, использовал push-инструкции для проталкивания стека, в результате чего получался гораздо более компактный код, не говоря уже о том, что это самый естественный способ для передачи аргументов для stdcall. Тем не менее, GCC упорно использует "мы" инструкцию для перемещения в каждом месте, вручную, при смещениях относительно ESP, потому что он должен держать указатель стека полностью статичным. stdcall сделан простым для вызывающей стороны, и, тем не менее, GCC полностью упускает суть stdcall, так как он генерирует этот дерьмовый код при взаимодействии с ним. Что еще хуже, поскольку указатель стека является статическим, он все еще использует указатель кадра? Просто почему?

Я пробовал -mpush-args, это ничего не делает.

Я также заметил, что если я сделаю свой стек достаточно большим, чтобы он превышал страницу (4096 байт), GCC добавит пролог с функцией, которая делает только стек по битам или каждые 4096 байт с нулем (который ничего не делает), Я предполагаю, что это касается касания стека и автоматической фиксации памяти с ошибками страницы, если стек был зарезервирован? К сожалению, он делает это, даже если я установил начальную фиксацию стека (не резервную) достаточно высокой, чтобы удерживать мой стек, не говоря уже об этом, вообще не нужно. Избыточный код в лучшем виде.

Эти ошибки в GCC? Или что-то мне не хватает в настройках? Должен ли я использовать что-то еще? Пожалуйста, скажите мне, если я пропускаю некоторые варианты.

Я серьезно надеюсь, что мне не придется создавать встроенный макрос asm только для того, чтобы вызывать функции stdcall и использовать инструкции push (и это также позволит избежать указателя кадра). Это звучит по-настоящему излишне для чего-то такого базового, что должно быть в современных компиляторах. И да, я использую GCC 4.8.1, поэтому не старая версия.

В качестве дополнительного вопроса, возможно ли заставить GCC не сохранять регистры в стеке при прологе функции? Я использую свою собственную точку прямого входа с аргументом -nostartfiles, потому что это чистое приложение Windows, и оно прекрасно работает без стандартного запуска lib. Если я использую атрибут((noreturn)), он отбрасывает эпилог, восстанавливающий регистры, но все равно помещает их в стек при прологе, я не знаю, есть ли способ заставить его не сохранять регистры для этой точки входа функция. В любом случае это не имеет большого значения, я думаю, это будет более полным. Спасибо!

2 ответа

Решение

См. Ответ Заставить GCC поместить аргументы в стек перед вызовом функции (используя инструкцию PUSH).

Т.е. попробуй -mpush-args -mno-accumulate-outgoing-args, Это также может потребовать -mno-stack-arg-probe если gcc жалуется.

Похоже, что поставляет -mpush-args -mno-аккумулировать-исходящие-args -mno-stack-arg-probe работает, особенно последний. Теперь код более чистый и более нормальный, как и другие компиляторы, и он использует PUSH для аргументов, даже облегчая таким образом отслеживание в OllyDbg.

К сожалению, это заставляет использовать глупый указатель фрейма даже в небольших функциях, которые ему абсолютно не нужны. Серьезно, есть ли способ полностью заставить GCC отключить указатель кадра?!

Другие вопросы по тегам