c - 通过无法优化的标头嵌入字符串
问题描述
在开发仅包含标头的库时,我想确保给定的字符串嵌入到使用我的标头的所有二进制文件中,即使编译器配置为优化未使用的常量,并且二进制文件被剥离。
嵌入不应该有任何副作用(除了使生成的二进制文件更大一点)。
我不知道人们将如何使用标题,但是
- 标头可能包含在多个编译单元中,全部链接到一个二进制文件中
- 目标平台是 Linux/macOS/Windows
- 编译器很可能是 gcc/clang/MSVC
我的微不足道的尝试相当于:
static char frobnozzel_version_string[] = "Frobnozzel v0.1; © 2019 ACME; GPLv3";
...,但是在构建过程中很容易删除该字符串(因为实际上没有使用该字符串,所以它很容易成为优化编译器的牺牲品)。
所以问题是:是否可以在任何包含给定标头的二进制文件中嵌入一个字符串,该字符串不会被通常的构建“发布”二进制文件的策略优化/剥离?
我知道,使用该库的任何人都可以(手动)删除我放入的任何内容,但我们假设,人们只是“按原样”使用标题。
上下文:有问题的标题是在GPL下发布的,我希望能够检查用户是否真的遵守了许可。
解决方案
您可以在标题中嵌入程序集伪操作,它应该保留(尽管它从未使用过):
asm(".ascii \"Frobnozzel v0.1; © 2019 ACME; GPLv3\"\n\t");
请注意,这是特定于 GCC/Clang 的。
MSVC 的替代方法是使用#pragma comment
or __asm db
:
__asm db "Frobnozzel v0.1; © 2019 ACME; GPLv3"
#pragma comment(user, "Frobnozzel v0.1; © 2019 ACME; GPLv3")
这是一个例子:
chronos@localhost ~/Downloads $ cat file.c
#include <stdio.h>
#include "file.h"
int main(void)
{
puts("The string is never used.");
}
chronos@localhost ~/Downloads $ cat file.h
#ifndef FILE_H
#define FILE_H 1
#if defined(__GNUC__)
asm(".ascii \"Frobnozzel v0.1; © 2019 ACME; GPLv3\"\n\t");
#elif defined(_MSC_VER)
# if defined(_WIN32)
__asm db "Frobnozzel v0.1; © 2019 ACME; GPLv3"
# elif defined(_WIN64)
# pragma comment(user, "Frobnozzel v0.1; © 2019 ACME; GPLv3")
# endif
#endif
chronos@localhost ~/Downloads $ gcc file.c
chronos@localhost ~/Downloads $ grep "Frobnozzel v0.1; © 2019 ACME; GPLv3" a.out
Binary file a.out matches
chronos@localhost ~/Downloads $
将gcc
命令替换为clang
,结果是一样的。
对于 64 位 Windows,这需要替换user
为已弃用的exestr
或创建将字符串嵌入可执行文件的资源文件。因此,链接时字符串将被删除。
推荐阅读
- bash - 用于 RNAseq 比对的 Bash For Loop
- windows - 创建新图像时无法在 docker 中 cd 到 /
- jestjs - 如何让 Jest 获取我的 Kotlin-js 测试?
- ios - TestFlight 用户未收到 Firebase 云消息 - iOS
- function - 收集未定义的参数 PowerShell
- azure - Azure Devops - 服务主体手动设置?
- sql - 如何通过表名获取表?
- android-studio - 无法从 Android Studio 安装生成的构建 apk
- postgresql - PostgreSQL“如果不存在”总是抛出语法错误
- python - 期望缩进块 Python 脚本压缩