有时候我们会想要将一些额外的信息写入c程序,如代码版本信息,好进行调试等工作。

一种办法是把版本信息写入源码中,然后通过接口去获取,如以下的c代码:

#define VERSION "v1.0"
void dump_version() {
    puts(VERSION);
}

这种方式必须要执行这个文件才能获取到版本号,我下面提供另一个思路,通过内联汇编把版本信息编译到目标的comment区来记录。

先做一个小实验,将以下C代码存为version.c文件:

// version.c
__asm__(".section .comment");
__asm__(".string \"Version: v1.0\"");

使用gcc编译:

gcc -c version.c -o version.o

然后通过readelf命令读取:

readelf -p .comment version.o

结果为:

String dump of section '.comment':
  [     0]  Version: v1.0
  [     f]  GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0

使用-Qn命令可以让gcc不编译自身信息(第二段信息)。

将以上过程写成一个脚本,如下:

#!/bin/sh

DATE=$(date +"%Y-%m-%d %H:%M:%S")
HASH=$(git rev-parse HEAD)
TAG=$(git describe --tags)

mkdir -p build
SRC_FILE=build/version.c
TARGET_FILE=build/version.o

(
    cat <<EOF
__asm__(".section .comment");
__asm__(".string \"DATE: $DATE\"");
__asm__(".string \"GIT: $HASH $TAG\"");
__asm__(".section .text");
EOF
) >$SRC_FILE

gcc -Qn -c $SRC_FILE -o $TARGET_FILE

然后在Makefile文件中,每次编译前执行一下这个脚本,并在链接的命令中,把build/version.o也加进去,就大功告成了。

其中调用了git命令获取当前仓库的信息,这里也列出了其他的git命令,供参考。