Конечная цель - сравнить 2 двоичных файла, созданных из одного и того же источника в одной и той же среде, и определить, что они действительно функционально эквивалентны.
Одно из приложений для этого - сосредоточить время контроля качества на вещах, которые действительно менялись между выпусками, а также на мониторинге изменений в целом.
MSVC в тандеме с форматом PE, естественно, делает это очень трудным.
Пока что я нашел и нейтрализовал эти вещи:
- Отметка времени и контрольная сумма PE
- Запись в каталоге электронной подписи
- Отметка времени раздела отладчика
- Подпись PDB, возраст и путь к файлу
- Отметка времени ресурсов
- Все версии файлов / продуктов в ресурсе VS_VERSION_INFO
- Раздел цифровой подписи
Я разбираю PE, нахожу смещения и размеры для всех этих вещей и игнорирую байтовые диапазоны при сравнении двоичных файлов. Работает как шарм (ну, для нескольких тестов, которые я запускал). Я могу сказать, что подписанный исполняемый файл с версией 1.0.2.0, построенный на Win Server 2008, равен неподписанному файлу версии 10.6.6.6, построенному на моем корпусе разработчика Win XP, при условии, что версия компилятора, все источники и заголовки одинаковы. Кажется, это работает для VC 7.1–9.0. (Для релизных сборок)
С одной оговоркой.
Абсолютные пути для обеих сборок должны быть одинаковыми должны иметь одинаковую длину.
cl.exe преобразует относительные пути в абсолютные и помещает их прямо в объекты вместе с флагами компилятора и т. д. Это оказывает непропорциональное влияние на всю двоичную систему. Изменение одного символа в пути приведет к тому, что один байт будет изменен здесь и там несколько раз по всему разделу .text (хотя я подозреваю, что многие объекты были связаны). Изменение длины пути приводит к значительному увеличению различий. Как в файлах obj, так и в связанном двоичном файле.
Похоже, что путь к файлу с флагами компиляции используется как своего рода хеш, который превращает его в связанный двоичный файл или даже влияет на порядок размещения несвязанных частей скомпилированного кода.
Итак, вот вопрос из трех частей (резюмированный как «что теперь?»):
Должен ли я отказаться от всего проекта и вернуться домой, потому что то, что я пытаюсь сделать, нарушает законы физики и корпоративную политику MS?
Предполагая, что я решаю проблему с абсолютным путем (на уровне политики или путем поиска волшебного флага компилятора), есть ли еще какие-то вещи, на которые мне следует обратить внимание? (такие вещи, как __TIME__ do означают измененный код, поэтому я не возражаю, чтобы те не игнорировались)
Есть ли способ заставить компилятор использовать относительные пути или заставить его думать, что путь не тот, что есть?
Причина последнего - красиво раздражающая файловая система Windows. Вы просто никогда не знаете, что при удалении нескольких гигабайт источников и объектов и метаданных svn произойдет сбой из-за мошеннической блокировки файла. По крайней мере, создание нового корня всегда удается, пока остается место. Одновременный запуск нескольких сборок тоже является проблемой. Запуск группы виртуальных машин, хотя и является довольно сложным решением.
Интересно, есть ли способ настроить виртуальную файловую систему для процесса и его дочерних процессов так, чтобы несколько деревьев процессов видели разные директории "C: \ build", принадлежащие только им, все в в то же время ... Легковесная виртуализация ...
ОБНОВЛЕНИЕ: мы недавно открыли источник этого инструмента на GitHub. См. Раздел Сравнить в документации.
--compare
вариант peparser. Но эта частьPDB ... file path
, похоже, работает не во всех случаях. Если я перестрою проект VC ++ 2015 после добавления _ 3_ в командную строку компоновщика (что приводит к удалению фактического пути из двоичного образа), затем peparse сообщает его какnot equivalent
исходной сборке. - person dxiv   schedule 09.05.2019