专家 - GCC 和 ld 链接器:重新初始化 .data 部分中包含的变量?

发布于 2024-09-12 03:59:39 字数 772 浏览 4 评论 0原文

在 C 程序中,我需要重新初始化所有全局变量,因为它们在程序启动时处于测试目的。

我想通过重新初始化功能重现 GCC 库从加载内存地址、LMA 到 VMA(运行时地址)的数据复制。 例如,如果 foo 变量被声明为全局变量并被初始化。如果我的重新初始化函数是 re_init():

#include <stdio.h> 
int foo1 = 42;
int foo2 = 777;

int main(){
    foo1 = 0;
    foo2 = 0;
    re_init();
    printf("foo1:%d and foo2:%d",foo1,foo2);
    return 0;
}

那么我想作为输出:

foo1:42 and foo2:777

我相信正确的方法是使用默认链接器文件,也许还有将启动值复制到 RAM 的启动代码。 那么,有了GCC(cygwin),我应该怎么做才能实现这一目标呢?

编辑:此页面似乎有更精确的内容: http:// resources.redhat.com/binutils/docs-2.12/ld.info/Output-Section-LMA.html#Output%20Section%20LMA

In an C program, I need to re-initialize all global variables as they where when the program starts for tests purpose.

I want to reproduce the data copy from Load Memory Address, LMA to VMA (run-time address) done by GCC libraries with a reinitialization function.
For example, if foo variables are declared as global and initialized. And if my re-initialization function is re_init():

#include <stdio.h> 
int foo1 = 42;
int foo2 = 777;

int main(){
    foo1 = 0;
    foo2 = 0;
    re_init();
    printf("foo1:%d and foo2:%d",foo1,foo2);
    return 0;
}

then I want to have as an output :

foo1:42 and foo2:777

I believe that the right way to do this is to the default linker file and maybe the startup code that copy initiation values to RAM.
So, with GCC (cygwin), what should I do to achieve this?

Edit: This page seems o have more precision on it :
http://sources.redhat.com/binutils/docs-2.12/ld.info/Output-Section-LMA.html#Output%20Section%20LMA

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

阳光下的泡沫是彩色的 2024-09-19 03:59:39

我不知道 cygwin 是如何做到这一点的,但一般来说,数据部分不会从其 LMA 复制到其 VMA;相反,可执行文件的相关块由内核内存映射到所需 VMA 处的 RAM,然后动态链接器执行指向数据部分的任何重定位。

因此,要从可执行文件的内容重新初始化数据部分,您必须复制足够的动态链接器和内核端可执行加载程序来: 查找可执行文件(这不一定是 argv[0]);解析其标头并找到数据部分;销毁旧的映射并在适当的 VMA 处重新创建它;重新进行所有搬迁;然后处理由于您从其下面拉出 C 库的运行时状态而引起的所有后果(这不仅是数据部分中您自己的全局变量,还存在 stdout 和 malloc 的主分配表之类的东西)。

对“unexec”和“undump”进行一些搜索,它们正在解决类似(但不相同)的问题,这可能会为您提供可以回收的代码。

I don't know exactly how cygwin does this, but in general, the data section is not copied from its LMA to its VMA; rather, the relevant chunk of the executable file is memory-mapped into RAM at the desired VMA by the kernel, and then the dynamic linker executes any relocations that point at the data section.

To reinitialize the data section from the contents of the executable, therefore, you're going to have to duplicate enough of the dynamic linker and kernel-side executable loader to: find the executable file (this is not necessarily argv[0]); parse its headers and locate the data section; destroy the old mapping and recreate it at the appropriate VMA; carry out all the relocations again; and then deal with all of the fallout caused by your having yanked the C library's runtime state out from under it (it's not only your own global variables in the data section, things like stdout and malloc's master allocation tables are there as well).

Do some searches on "unexec" and "undump", which are solving a similar (but not the same) problem, that might get you code you can recycle.

甜点 2024-09-19 03:59:39

你所走的道路充满了可移植性问题、错误和悲伤。

解决这个问题的最佳方法是:全局变量很糟糕!我会将所有代码分解出来,将状态存储在“上下文”结构中,并进行传递。这样重置“状态”只是制造一个新的“上下文”结构。

The path you're going is fraught with portability problems, bugs, and sadness.

Best way to fix this: globals are bad! I would factor all my code out to store state in a "context" struct, which is passed around. That way resetting the "state" is just manufacturing a new "context" struct.

渡你暖光 2024-09-19 03:59:39

这是另一个解决方案的想法,尽管我仍然认为消除全局状态是更好的解决方案。

通过宏在头文件中定义所有全局变量:

globals.h:

DEFINE_GLOBAL(int, foo, 5);
DEFINE_GLOBAL(char, bar, 'x');

main.c:

#include <stdio.h>

#define DEFINE_GLOBAL(type, name, initialvalue) type name = initialvalue
#include "globals.h"
#undef DEFINE_GLOBAL

void resetState() {
    #define DEFINE_GLOBAL(type, name, initialvalue) name = initialvalue
    #include "globals.h"
    #undef DEFINE_GLOBAL
}

我还没有测试过这个,所以它可能需要一些语法修正 - 但我认为这个概念是合理的。

Here's another idea for a solution, although I still think that eliminating the global state is a better one.

Define all your globals in a header file via macros:

globals.h:

DEFINE_GLOBAL(int, foo, 5);
DEFINE_GLOBAL(char, bar, 'x');

main.c:

#include <stdio.h>

#define DEFINE_GLOBAL(type, name, initialvalue) type name = initialvalue
#include "globals.h"
#undef DEFINE_GLOBAL

void resetState() {
    #define DEFINE_GLOBAL(type, name, initialvalue) name = initialvalue
    #include "globals.h"
    #undef DEFINE_GLOBAL
}

I haven't tested this, so it might need some syntax correction - but I think the concept is sound.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文