在运行时访问 build-id
Access build-id at runtime
我正在尝试弄清楚如何访问链接器在 运行 时生成的构建 ID。
从这个页面,https://linux.die.net/man/1/ld
当我构建如下测试程序时:
% gcc test.c -o test -Wl,--build-id=sha1
我可以看到构建 ID 存在于二进制文件中:
% readelf -n test
Displaying notes found in: .note.gnu.build-id
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 85aa97bd52ddc4dc2a704949c2545a3a9c69c6db
我想在 运行 时打印这个。
编辑:假设您无法访问加载 运行ning 进程的 elf 文件(权限、embedded/no 文件系统等)。
编辑:接受的答案有效,但链接器不一定必须将变量放在该部分的末尾。如果有办法获得指向该部分开头的指针,那会更可靠。
想通了。这是一个工作示例,
#include <stdio.h>
//
// variable must have an initializer
// https://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Variable-Attributes.html
//
// the linker places this immediately after the section data
//
char build_id __attribute__((section(".note.gnu.build-id"))) = '!';
int main(int argc, char ** argv)
{
const char * s;
s = &build_id;
// section data is 20 bytes in size
s -= 20;
// sha1 data continues for 20 bytes
printf(" > Build ID: ");
int x;
for(x = 0; x < 20; x++) {
printf("%02hhx", s[x]);
}
printf(" <\n");
return 0;
}
当我 运行 这样做时,我得到与 readelf 匹配的输出,
0 % gcc -g main.c -o test -Wl,--build-id=sha1 && readelf -n test | tail -n 5 && ./test
Displaying notes found in: .note.gnu.build-id
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: c5eca2cb08f4f5a31bb695955c7ebd2722ca10e9
> Build ID: c5eca2cb08f4f5a31bb695955c7ebd2722ca10e9 <
一种可能是使用链接器脚本获取 .note.gnu.build-id
部分的地址:
#include <stdio.h>
// These will be set by the linker script
extern char build_id_start;
extern char build_id_end;
int main(int argc, char **argv) {
const char *s;
s = &build_id_start;
// skip over header (16 bytes)
s += 16;
printf(" > Build ID: ");
for (; s < &build_id_end; s++) {
printf("%02hhx", *s);
}
printf(" <\n");
return 0;
}
在链接描述文件中,定义了符号build_id_start
和build_id_end
:
build_id_start = ADDR(.note.gnu.build-id);
build_id_end = ADDR(.note.gnu.build-id) + SIZEOF(.note.gnu.build-id);
然后可以编译代码 运行:
gcc build-id.c linker-script.ld -o test && readelf -n test | grep NT_GNU_BUILD_ID -A1 && ./test
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 7e87ff227443c8f2d5c8e2340638a2ec77d008a1
> Build ID: 7e87ff227443c8f2d5c8e2340638a2ec77d008a1 <
我找到了 build-id 可以在运行时获取 BuildId 的库。
auto path="/path/to/executable";
const struct build_id_note *note = build_id_find_nhdr_by_name(path);
if (!note) {
return std::nullopt;
}
ElfW(Word) len = build_id_length(note);
const uint8_t *build_id = build_id_data(note);
std::vector<byte> result(build_id,build_id+len);
我正在尝试弄清楚如何访问链接器在 运行 时生成的构建 ID。
从这个页面,https://linux.die.net/man/1/ld
当我构建如下测试程序时:
% gcc test.c -o test -Wl,--build-id=sha1
我可以看到构建 ID 存在于二进制文件中:
% readelf -n test
Displaying notes found in: .note.gnu.build-id
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 85aa97bd52ddc4dc2a704949c2545a3a9c69c6db
我想在 运行 时打印这个。
编辑:假设您无法访问加载 运行ning 进程的 elf 文件(权限、embedded/no 文件系统等)。
编辑:接受的答案有效,但链接器不一定必须将变量放在该部分的末尾。如果有办法获得指向该部分开头的指针,那会更可靠。
想通了。这是一个工作示例,
#include <stdio.h>
//
// variable must have an initializer
// https://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Variable-Attributes.html
//
// the linker places this immediately after the section data
//
char build_id __attribute__((section(".note.gnu.build-id"))) = '!';
int main(int argc, char ** argv)
{
const char * s;
s = &build_id;
// section data is 20 bytes in size
s -= 20;
// sha1 data continues for 20 bytes
printf(" > Build ID: ");
int x;
for(x = 0; x < 20; x++) {
printf("%02hhx", s[x]);
}
printf(" <\n");
return 0;
}
当我 运行 这样做时,我得到与 readelf 匹配的输出,
0 % gcc -g main.c -o test -Wl,--build-id=sha1 && readelf -n test | tail -n 5 && ./test
Displaying notes found in: .note.gnu.build-id
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: c5eca2cb08f4f5a31bb695955c7ebd2722ca10e9
> Build ID: c5eca2cb08f4f5a31bb695955c7ebd2722ca10e9 <
一种可能是使用链接器脚本获取 .note.gnu.build-id
部分的地址:
#include <stdio.h>
// These will be set by the linker script
extern char build_id_start;
extern char build_id_end;
int main(int argc, char **argv) {
const char *s;
s = &build_id_start;
// skip over header (16 bytes)
s += 16;
printf(" > Build ID: ");
for (; s < &build_id_end; s++) {
printf("%02hhx", *s);
}
printf(" <\n");
return 0;
}
在链接描述文件中,定义了符号build_id_start
和build_id_end
:
build_id_start = ADDR(.note.gnu.build-id);
build_id_end = ADDR(.note.gnu.build-id) + SIZEOF(.note.gnu.build-id);
然后可以编译代码 运行:
gcc build-id.c linker-script.ld -o test && readelf -n test | grep NT_GNU_BUILD_ID -A1 && ./test
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 7e87ff227443c8f2d5c8e2340638a2ec77d008a1
> Build ID: 7e87ff227443c8f2d5c8e2340638a2ec77d008a1 <
我找到了 build-id 可以在运行时获取 BuildId 的库。
auto path="/path/to/executable";
const struct build_id_note *note = build_id_find_nhdr_by_name(path);
if (!note) {
return std::nullopt;
}
ElfW(Word) len = build_id_length(note);
const uint8_t *build_id = build_id_data(note);
std::vector<byte> result(build_id,build_id+len);