2

在 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: //sources.redhat.com/binutils/docs-2.12/ld.info/Output-Section-LMA.html#Output%20Section%20LMA

4

3 回答 3

3

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

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

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

于 2010-08-01T23:22:55.437 回答
2

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

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

于 2010-08-01T23:28:38.173 回答
0

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

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

全局变量.h:

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

主.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
}

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

于 2010-08-01T23:31:37.937 回答