Определить, оптимизирован ли двоичный код C++

есть ли флаг или другой надежный метод для определения, был ли скомпилированный двоичный файл C++ скомпилирован с оптимизациями?

Я в порядке с решениями для компилятора.


Edit: это для системы развертывания сборки, которая может случайно развернуть двоичные файлы, которые не были построены должным образом. Водонепроницаемое решение маловероятно, но оно сэкономит некоторую боль (и деньги), если это может быть обнаружено некоторое время.

компилятор часто будьте gcc, иногда sun, и если есть решение MSVC, я не хочу исключать это в интересах сообщества.

10 ответов


последние версии GCC имеют способ сообщить, какие флаги использовались для компиляции двоичного (третий пункт).

существует связанный переключатель командной строки (--fverbose-asm), который "записывает только информацию в выходной файл ассемблера как комментарии, поэтому информация никогда не достигает объектного файла."Переключатель --frecord-GCC-switches" вызывает командную строку, которая использовалась для вызова компилятора, для записи в объектный файл, который создан."


метод, который мы используем, - это просто создать символ, который появляется в каждой библиотеке только при построенной отладке:

// included_by_everything.h
#ifdef (_DEBUG)
extern "C" __declspec( dllexport ) void WasBuiltInDebug() {}
#else
// nothing!
#endif

и затем при загрузке каждого модуля во время выполнения (или в триггере Perforce) мы можем спросить двоичный файл, если он отлажен, просто ища этот символ:

bool IsDebugDLL( HMODULE DllHandle )
{
  // this system call returns a nonzero address if it can 
  // find the symbol, and NULL otherwise:
  return GetProcAddress( DllHandle , "WasBuiltInDebug" );
}

Возможное Эвристическое Решение

Если бы мне дали эту задачу, и это доказало бы, что это resonable задача. Я бы выполнил "частотный анализ" шаблонов, увиденных в исполняемой разборке. Как программист, я могу различать оптимизированный и неоптимизированный (отладочный) код на первый взгляд. Я бы попытался формализовать процесс принятия решений, с Visual Studio и платформой x86 типичными функциями, замеченными в неоптимизированном exe, были бы:

  • функции с полным прологом / эпилогом (ebp на основе стека кадров)
  • много mov-s из / в память (все переменные, помещенные в память)

это определенно не 100 %, но с более длинным exe я ожидал бы, что результаты будут довольно надежными.

Я предполагаю, что для других платформ x86, включая GCC, правила будут похожи, если не одинаковы, и для других платформ можно найти аналогичные правила.

другие эвристики, такие как обнаружение библиотеки времени выполнения может работать также, в зависимости от настроек компилятора.

задача звучит глупо

тем не менее, я думаю, что такая задача "пахнет", и в большинстве случаев было бы разумно полностью избежать этого. Если вы приведете реальную причину такой задачи, очень вероятно, что будет найдено какое-то разумное решение.


в Windows вы можете проверить, удалена ли отладочная информация из двоичного файла. Если вы исследуете двоичное изображение для заголовка COFF, есть 2-байтовый флаговый блок, называемый характеристиками со смещением байта 18 от заголовка COFF. Если флаг

 IMAGE_FILE_DEBUG_STRIPPED = 0x0200

устанавливается, после чего отладочная информация удаляется из файла изображения.

Это можно сделать с помощью тривиального 2-байтового чтения из смещения файла 0x52 и проверки, установлен ли флаг.

флаг можно проверить как следует

 short flag_block;

 FILE * p_image_file = fopen (...); 

 fseek(p_image_file,0x52,SEEK_SET);

 fread(&flag_block,2,1,p_image_file);

 if(flag_block & 0x0200 > 0)
    then debug info is stripped

Вы можете найти формат документа Windows PE от Microsoft, который описывает его более подробно для вас, чтобы вычислить смещение байта для чтения из etc...


вы не упоминаете конкретную платформу, поэтому ответ может быть да. Но для большинства распространенных платформ ответ-нет.



для Microsoft C++ можно предположить, что оптимизация была отключена, если исполняемый файл ссылается на отладочные версии DLL во время выполнения. Но это не гарантия.


по моему опыту, единственный надежный способ-изучить саму разборку если вы не знаете компилятор. Сначала попробуйте сбросить все строки с вашим любимым инструментом и искать подсказки в связанных именах библиотек и экспортированных символов. В противном случае ищите общие последовательности команд, которые в основном выбрасываются после оптимизации, такой как пролог кадра стека и упорядоченное и легкое для понимания использование регистра. Если такие инструменты, как ollydbg, путаются в том, где начинается функция и заканчивается, есть хороший шанс, что двоичный файл компилируется с оптимизацией.

изучение вывода декомпилятора также может помочь. Последний раз, когда я проверял, они были не лучше, чем дизассемблер, но с тех пор все могло улучшиться.


Я был бы удивлен, если бы вы уже не делали что-то подобное, но:

Если Вы" доверяете " системе сборки, поместите параметры, используемые для сборки, в строку, которую вы можете извлечь из запущенной программы. (т. е. из --version или диалогового окна about)

Это не обнаружит проблем с неоптимизированными объектными файлами, попадающими в сборку из-за сломанной системы сборки, но это позволит вам легко отличить сборку разработчика от сборки выпуска.

ваш релиз затем процесс может включать проверку версии, чтобы убедиться, что она не является отладочной/неоптимизированной.


Я уверен, что нет никакой возможности. Если у вас нет специальных знаний о функции внутри, вы можете проверить, является ли последовательность кода оптимальной или нет.


возможно, вы могли бы использовать другой индикатор, чтобы определить, развертываете ли вы правильный двоичный файл. например,

  • Debug info: может быть, ваши двоичные файлы выпуска отличаются тем, что у них нет отладочной информации? Вы можете проверить это с помощью elfdump или gdb.
  • Stripped: если ваши двоичные файлы выпуска удалены, вы можете использовать" файл", чтобы проверить это