Эксперты - GCC и ld linker: реинициализация переменных, содержащихся в разделе .data? - PullRequest
2 голосов
/ 01 августа 2010

В программе на C мне нужно повторно инициализировать все глобальные переменные, когда они запускаются для целей тестирования.

Я хочу воспроизвести копию данных с адреса загрузки памяти, LMA в VMA (адрес времени выполнения), выполненный библиотеками GCC с функцией повторной инициализации.Например, если переменные 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

Я считаю, что правильный способ сделать этофайл компоновщика по умолчанию и, возможно, код запуска, который копирует значения инициализации в ОЗУ.Итак, что я должен сделать с GCC (cygwin), чтобы добиться этого?

Редактировать: Кажется, на этой странице больше точности: http://sources.redhat.com/binutils/docs-2.12/ld.info/Output-Section-LMA.html#Output%20Section%20LMA

Ответы [ 3 ]

3 голосов
/ 02 августа 2010

Я не знаю точно, как Cygwin делает это, но в целом раздел данных не копируется из его LMA в его VMA; скорее соответствующий ядро ​​исполняемого файла сопоставляется с памятью в ОЗУ в желаемом VMA ядром, а затем динамический компоновщик выполняет любые перемещения, которые указывают на секцию данных.

Для повторной инициализации раздела данных из содержимого исполняемого файла, следовательно, вам придется продублировать достаточно динамического компоновщика и исполняемого загрузчика на стороне ядра, чтобы: найти исполняемый файл (это не обязательно argv [0 ]); разобрать его заголовки и найти раздел данных; уничтожить старое отображение и воссоздать его в соответствующем VMA; выполнить все переезды снова; а затем разобраться со всеми последствиями, вызванными тем, что вы выдернули из-под нее состояние времени выполнения библиотеки C (это не только ваши собственные глобальные переменные в разделе данных, такие вещи, как stdout и основные таблицы распределения malloc). 1003 *

Выполните некоторые поиски по "unexec" и "undump", которые решают аналогичную (но не ту же) проблему, которая может получить код, который вы можете переработать.

2 голосов
/ 02 августа 2010

Путь, по которому вы идете, чреват проблемами переносимости, ошибками и грустью.

Лучший способ исправить это: глобальные ошибки плохие!Я бы выделил весь свой код для хранения состояния в «контекстной» структуре, которая передается.Таким образом, сброс «состояния» - это просто создание новой структуры «контекста».

0 голосов
/ 02 августа 2010

Вот еще одна идея для решения, хотя я все еще думаю, что устранение глобального состояния лучше.

Определите все ваши глобальные переменные в заголовочном файле с помощью макросов:

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
}

Я не проверял это, поэтому может потребоваться некоторая коррекция синтаксиса - но я думаю, что концепция обоснована.

...