CryoPID 如何创建 ELF 标头,或者是否有一种简单的方法来生成 ELF?
我正在尝试用 C 语言编写一个检查点/重新启动程序,并且正在研究 CryoPID 的代码以了解如何重新启动进程。在它的代码中,cryoPID 创建了要在使用某些全局变量的函数中重新启动的进程的 ELF 标头,这确实令人困惑。
我一直在寻找一种简单的方法来创建 ELF 可执行文件,甚至尝试了 libelf,但我发现大多数时候这些程序的文档中一些必要的信息是模糊的,我无法理解如何做到这一点。因此,在这件事上的任何帮助都会很棒。
看到cryoPID的代码,我发现它以一种简单的方式完成了整个创建,不必设置所有标头字段等。但我似乎无法理解它使用的代码。 首先,在创建 ELF 的函数中,以下代码是相关的(位于 arch-x86_64/elfwriter.c 中):
Elf64_Ehdr *e;
Elf64_Shdr *s;
Elf64_Phdr *p;
char* strtab;
int i, j;
int got_it;
unsigned long cur_brk = 0;
e = (Elf64_Ehdr*)stub_start;
assert(e->e_shoff != 0);
assert(e->e_shentsize == sizeof(Elf64_Shdr));
assert(e->e_shstrndx != SHN_UNDEF);
s = (Elf64_Shdr*)(stub_start+(e->e_shoff+(e->e_shstrndx*e->e_shentsize)));
strtab = stub_start+s->sh_offset;
stub_start 是一个全局变量,在 Cryopid.h 中使用宏 declare_writer 定义:
#define declare_writer(s, x, desc) \
extern char *_binary_stub_##s##_start; \
extern int _binary_stub_##s##_size; \
struct stream_ops *stream_ops = &x; \
char *stub_start = (char*)&_binary_stub_##s##_start; \
long stub_size = (long)&_binary_stub_##s##_size
该宏在 writer_* 中使用.c 是实现文件编写器的文件。例如,在 writer_buffered.c 中,使用以下代码调用宏:
struct stream_ops buf_ops = {
.init = buf_init,
.read = buf_read,
.write = buf_write,
.finish = buf_finish,
.ftell = buf_ftell,
.dup2 = buf_dup2,
};
declare_writer(buffered, buf_ops, "Writes an output file with buffering");
因此,stub_start 被声明为未初始化的全局变量(上面的代码不在任何函数中),并且看到 declare_writer 中的所有变量都没有在在代码中,我假设 Stub_start 只是指向 .bss 部分的某些部分,但看起来 CryoPID 使用它就像指向它自己的 ELF 标头一样。
任何人都可以帮助我解决这个问题或以任何方式帮助我轻松创建 ELF 标头吗?
I'm trying to do a checkpoint/restart program in C and I'm studying cryoPID's code to see how a process can be restarted. In it's code, cryoPID creates the ELF header of the process to be restarted in a function that uses some global variable and it's really confusing.
I have been searching for an easy way to create an ELF executable file, even trying out libelf, but I find that most of the times some necessary information is vague in the documentation of these programs and I cannot get to understand how to do it. So any help in that matter would be great.
Seeing cryoPID's code I see that it does the whole creation in an easy way, not having to set all header fields, etc. But I cannot seem to understand the code that it uses.
First of all, in the function that creates the ELF the following code is relevant (it's in arch-x86_64/elfwriter.c):
Elf64_Ehdr *e;
Elf64_Shdr *s;
Elf64_Phdr *p;
char* strtab;
int i, j;
int got_it;
unsigned long cur_brk = 0;
e = (Elf64_Ehdr*)stub_start;
assert(e->e_shoff != 0);
assert(e->e_shentsize == sizeof(Elf64_Shdr));
assert(e->e_shstrndx != SHN_UNDEF);
s = (Elf64_Shdr*)(stub_start+(e->e_shoff+(e->e_shstrndx*e->e_shentsize)));
strtab = stub_start+s->sh_offset;
stub_start is a global variable defined with the macro declare_writer in cryopid.h:
#define declare_writer(s, x, desc) \
extern char *_binary_stub_##s##_start; \
extern int _binary_stub_##s##_size; \
struct stream_ops *stream_ops = &x; \
char *stub_start = (char*)&_binary_stub_##s##_start; \
long stub_size = (long)&_binary_stub_##s##_size
This macro is used in writer_*.c which are the files that implement writers for files. For example in writer_buffered.c, the macro is called with this code:
struct stream_ops buf_ops = {
.init = buf_init,
.read = buf_read,
.write = buf_write,
.finish = buf_finish,
.ftell = buf_ftell,
.dup2 = buf_dup2,
};
declare_writer(buffered, buf_ops, "Writes an output file with buffering");
So stub_start gets declared as an uninitialized global variable (the code above is not in any function) and seeing that all the variables in declare_writer are not set in any other part of the code, I assume that stub_start just point to some part of the .bss section, but it seems like cryoPID use it like it's pointing to its own ELF header.
Can anyone help me with this problem or assist me in anyway to create ELF headers easily?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如评论中提到的,它使用类似于 objcopy 的东西来设置这些变量(它不使用 objcopy 命令,但我认为自定义链接器可能是“设置”变量的链接器)。无法确切找到什么,但我可以通过映射先前编译的可执行文件并使用该映射设置变量stub_start和stub_size来重现该行为。
As mentioned in the comment, it uses something similar to objcopy to set those variables (it doesn't use the objcopy command, but custom linkers that I think could be the ones that area "setting" the variables). Couldn't exactly find what, but I could reproduce the behavior by mmap'ing an executable file previously compiled and setting the variables stub_start and stub_size with that map.