gcc — двоичная идентификация C ++ (манифест)

У нас есть большой набор проектов C ++ (GCC, Linux, в основном статические библиотеки) с множеством зависимостей между ними. Затем мы скомпилируем исполняемый файл с использованием этих библиотек и развернем двоичный файл на внешнем интерфейсе. Было бы чрезвычайно полезно иметь возможность идентифицировать этот двоичный файл. В идеале нам нужен небольшой скрипт, который бы извлекал следующую информацию непосредственно из двоичного файла:

$ident binary
$binary : Product=PRODUCT_NAME;Version=0.0.1;Build=xxx;User=xxx...
$  dependency: Product=PRODUCT_NAME1;Version=0.1.1;Build=xxx;User=xxx...
$  dependency: Product=PRODUCT_NAME2;Version=1.0.1;Build=xxx;User=xxx...

Таким образом, он должен отображать всю информацию для самого двоичного файла и для всех его зависимостей.

В настоящее время наш подход:

  1. Во время компиляции для каждого продукта мы генерируем Manifest.h и Manifest.cpp, а затем внедряем Manifest.o в двоичный файл.

  2. Подлинный скрипт анализирует целевой двоичный файл, находит там сгенерированный материал и печатает эту информацию

Однако этот подход не всегда надежен для разных версий gcc.
Я хотел бы спросить SO сообщества — есть ли лучший подход для решения этой проблемы?

Спасибо за любой совет

4

Решение

Один из уловов с хранением данных в исходном коде (ваш Manifest.h а также .cpp) является лимитом размера для литеральных данных, который зависит от компилятора.

Мое предложение заключается в использовании ld, Это позволяет вам хранить произвольные двоичные данные в вашем файле ELF (как и objcopy). Если вы предпочитаете написать собственное решение, взгляните на libbfd.

Допустим, у нас есть hello.cpp содержащий обычный пример C ++ «Hello world». Теперь у нас есть следующий файл make (GNUmakefile):

hello: hello.o hello.om
$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@

%.om: %.manifest
ld -b binary -o $@ $<

%.manifest:
echo "$@" > $@

Здесь я делаю этап связывания, потому что я хочу, чтобы манифест (после преобразования в формат объекта ELF) также был связан с двоичным файлом. Поскольку я использую суффиксные правила, это один путь, другие, безусловно, возможны, включая лучшую схему именования для манифестов, где они также заканчиваются как .o файлы и GNU make могут понять, как их создать. Здесь я подробно рассказываю о рецепте. Итак, мы имеем .om файлы, которые являются манифестами (произвольными двоичными данными), созданными из .manifest файлы. Рецепт утверждает, что преобразовать двоичный вход в объект ELF. Рецепт создания .manifest Сам по себе просто передает строку в файл.

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

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

Приведенный выше файл make не учитывает зависимости — точнее, он никак не помогает создавать список зависимостей. Вы, вероятно, можете заставить GNU помочь вам в этом, если вы четко выразите свои зависимости для каждой цели (то есть статических библиотек и т. Д.). Но, возможно, не стоит идти по этому пути …

Также посмотрите на:


Если вам нужны конкретные имена для символов, сгенерированных из данных (в вашем случае манифест), вам нужно использовать немного другой маршрут и использовать метод, описанный Джоном Рипли. Вот.

Как получить доступ к символам? Легко. Объявите их как внешние (C linkage!) Данные и затем используйте их:

#include <cstdio>

extern "C" char _binary_hello_manifest_start;
extern "C" char _binary_hello_manifest_end;

int main(int argc, char** argv)
{
const ptrdiff_t len = &_binary_hello_manifest_end - &_binary_hello_manifest_start;
printf("Hello world: %*s\n", (int)len, &_binary_hello_manifest_start);
}

Символы являются точными символами / байтами. Вы также можете объявить их как char[], но это приведет к проблемам в будущем. Например. для printf вызов.

Причина, по которой я сам вычисляю размер, заключается в том, что а.) Я не знаю, гарантированно ли буфер завершен нулем, и б.) Я не нашел никакой документации по взаимодействию с *_size переменная.

Примечание: * в строке формата говорит printf что он должен прочитать длину строки из аргумента, а затем выбрать следующий аргумент в качестве строки для печати.

5

Другие решения

Вы можете вставить любые данные в .comment раздел в вашей выходной двоичный файл. Вы Можно сделайте это с компоновщиком после факта, но, вероятно, проще поместить его в ваш код C ++, например:

 asm  (".section .comment.manifest\n\t"".string \"hello, this is a comment\"\n\t"".section .text");

int main() {
....

asm заявление должно идти вне любая функция, в этом случае. Это должно работать до тех пор, пока ваш компилятор помещает нормальные функции в .text раздел. Если это не так, вы должны сделать очевидную замену.

Линкер должен собрать все .comment.manifest разделы на один BLOB-объект в конечном двоичном файле. Вы можете извлечь их из любого .o или исполняемый с этим:

objdump -j .comment.manfest -s example.o
2

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

Мы используем пакеты debian, которые содержат всю необходимую информацию:

  • Полный список изменений, который включает в себя:
    • авторы;
    • версии;
    • краткие описания и временные метки изменений.
  • Информация о зависимости:
    • список всех пакетов, которые должны быть установлены, чтобы текущий работал правильно.
  • Сценарии установки, которые устанавливают среду для пакета.

Я думаю, что вам не нужно создавать манифесты по-своему, как только готовое решение уже существует. Вы можете взглянуть на Пакет Debian HowTo здесь.

0
По вопросам рекламы [email protected]