Как мне узнать, откуда раздел .data должен получить данные инициализации?(компоновщик gcc) - PullRequest
8 голосов
/ 15 февраля 2012

При создании проекта mcu на основе gcc на основе gcc вам необходимо позаботиться об инициализации разделов .data и .bss во время запуска.

Раздел .bss довольно прост, так как я просто заполняю весь раздел до 0. Но переменные в разделе .data должны иметь свои данные инициализации в rom / flash и копироваться во время запуска.

Как узнать, где можно найти данные со значениями инициализации?

Давайте рассмотрим пример.

Допустим, я создаю две глобальные переменные в main.c

unsigned int my_global_variable_one  = 1;
unsigned int my_global_variable_two  = 2;

Тогда я могу использовать objdump для объектного файла, чтобы увидеть, в каком разделе они будут находиться, но я не могу найти ничего в objdump out, куда должны помещаться данные инициализации.

$ arm-none-eabi-objdump --syms main.o | grep my_global_variable
00000000 g     O .data  00000004 my_global_variable_one
00000004 g     O .data  00000004 my_global_variable_two

Тогда я могу посмотреть на итогового эльфа для всей системы, в данном случае main.elf.

$ arm-none-eabi-nm -n main.elf | grep my_global_variable
20000000 D my_global_variable_one
20000004 D my_global_variable_two

Где я могу найти, где они находятся, чтобы я мог скопировать данные? Что мне нужно добавить в мой скрипт компоновщика?

Это должно быть что-то вроде .text или .rodata, но откуда мне знать?

Как я могу проверить, где находятся данные инициализации для my_global_variable_one?

Можно ли найти эти данные с помощью любой из команд binutils, таких как readelf или objdump?

/ Спасибо


Это на mc stm32 (Cortex M3), и используется версия gcc для CodeBench.

1 Ответ

11 голосов
/ 15 февраля 2012

Компилятор помещает весь код и некоторые данные только для чтения в раздел .text.Также может быть раздел .rodata.Вы можете сделать так, чтобы ваш скрипт компоновщика поместил в адрес ПЗУ что-то вроде этого:

. = <rom-base-address>;
.rodata : { *(.rodata) }
<other read-only sections go here>
.text   : { *(.text) }

Компилятор помещает все начальные значения доступных для записи данных в раздел .data и все символы, которые не имеютначальное значение в .bss..bss просто, вы просто помещаете это в оперативную память..data хочет быть в ОЗУ во время выполнения, но в ПЗУ во время загрузки, и скрипт компоновщика позволяет сделать это с ключевым словом AT:

. = <ram-base-address>;
.bss  : { *(.bss) }
.data : AT ( ADDR (.text) + SIZEOF (.text) )
        { *(.data) }

Это означает, что данныераздел теперь имеет разные LMA и VMA (адрес загрузки памяти / адрес виртуальной памяти).Ваша программа будет ожидать найти данные в VMA (во время выполнения), но эти данные действительно будут существовать в LMA (вам, возможно, придется научить ваш флешер это делать), что сразу после раздела .text.

Если вам нужно выяснить, куда копировать и откуда, вы можете создать указатели в скрипте компоновщика.Итак, измените приведенный выше пример следующим образом:

.data : AT ( ADDR (.text) + SIZEOF (.text) )
        { _data_lma = LOADADDR(.data); _data_vma = .;
          *(.data);
          _data_size = SIZEOF (.data);}

Затем вы можете сделать memcpy (_data_vma, _data_lma, _data_size) в своем коде запуска (хотя вам, возможно, придется кодировать это вручную в ассемблере?)ваша программа как постоянные глобальные переменные, которые разрешаются во время соединения.Итак, в вашем ассемблерном коде у вас может быть что-то вроде:

_data_lma_k:
   .long _data_lma

Тогда число будет жестко запрограммировано в разделе .text.Конечно, синтаксис ассемблера может отличаться на вашей платформе.

Для получения дополнительной информации см. Руководство по компоновщику здесь

...