C++二进制标识(清单)

nog*_*ard 4 c++ binary gcc identity manifest

我们有一大堆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...
Run Code Online (Sandbox Code Playgroud)

所以它应该显示二进制本身及其所有依赖项的所有信息.

目前我们的方法是:

  1. 在为每个产品编译期间,我们生成Manifest.h和Manifest.cpp,然后将Manifest.o注入二进制文件

  2. ident脚本解析目标二进制文件,在那里找到生成的东西并打印此信息

然而,对于不同版本的gcc,这种方法并不总是可靠的.我想问SO社区 - 有没有更好的方法来解决这个问题?

谢谢你的建议

0xC*_*22L 5

在源代码(您的Manifest.h.cpp)中存储数据的捕获之一是文字数据的大小限制,这取决于编译器.

我的建议是使用ld.它允许您在ELF文件中存储任意二进制数据(也是如此objcopy).如果您更喜欢编写自己的解决方案,请查看libbfd.

让我们说我们有一个hello.cpp包含通常的C++"Hello world"示例.现在我们有以下make file(GNUmakefile):

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

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

%.manifest:
    echo "$@" > $@
Run Code Online (Sandbox Code Playgroud)

我在这里做的是分离链接阶段,因为我希望清单(在转换为ELF对象格式之后)链接到二进制文件中.由于我使用后缀规则,这是一种方法,其他的当然是可能的,包括更好的命名方案,它们最终也作为.o文件,GNU make可以弄清楚如何创建它们.在这里,我明确了解食谱.所以我们有.om文件,它们是从.manifest文件创建的清单(任意二进制数据).配方声明将二进制输入转换为ELF对象.创建.manifest自身的方法只是将一个字符串传递给文件.

显然,您的案例中棘手的部分不是存储清单数据,而是生成清单数据.坦率地说,我对你的构建系统知之甚少,甚至试图为这.manifest一代建议一个配方.

无论你投入到你的.manifest文件或许应该是可以被你提到的脚本解释一些结构化文本,或者甚至可以是由二进制文件本身的输出,如果你执行一个命令行开关(和无视.so文件和.so文件攻入表现得像普通的可执行文件从shell运行时).

上面的make文件没有考虑依赖项 - 或者说它不会帮助您以任何方式创建依赖项列表.如果你为每个目标(即静态库等)清楚地表达你的依赖关系,你可以强迫GNU make帮助你.但采取这条路线可能不值得......

另请看:


如果你想从数据生成的符号的特定名称(在你的案件清单),你需要使用一个稍微不同的路线和使用由约翰·里普利描述的方法在这里.

如何访问符号?简单.将它们声明为外部(C链接!)数据,然后使用它们:

#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);
}
Run Code Online (Sandbox Code Playgroud)

符号是确切的字符/字节.您也可以将它们声明为char[],但这会导致问题.例如,printf电话.

我自己计算大小的原因是因为a.)我不知道缓冲区是否保证是零终止和b.)我没有找到任何与*_size变量接口的文档.

旁注:*格式字符串中的字符串告诉printf它应该从参数中读取字符串的长度,然后选择下一个参数作为要打印的字符串.