Я бы сказал, что неплохо разбираюсь в C ++, однако я новичок в скриптах компоновщика и не совсем уверен, что делаю неправильно. Прежде всего, это мой скрипт компоновщика:
ENTRY(ISR_Reset)
MEMORY {
FLASH (rx) : ORIGIN = 0x80000, LENGTH = 128K
RAM (rwx) : ORIGIN = 0x20000000 LENGTH = 36K
}
SECTIONS {
.text : {
*(.vector_table)
*(.text.startup)
*(.text)
*(.rodata)
} > FLASH
__data_flash_source__ = ALIGN(4);
.data : AT(__data_flash_source__) {
__data_section_start__ = .;
*(.data)
*(.init_array)
__data_section_end__ = .;
__ram_end__ = ORIGIN(RAM) + LENGTH(RAM);
} > RAM
.bss : {
*(.bss)
} > RAM
}
Я копирую данные из FLA SH в RAM между __data_section_start__
и __data_section_end__
, а затем обнуляю остальную часть RAM. Я использую следующую команду для компиляции моего кода: arm-none-eabi-g++.exe .\src\start.s .\src\main.cpp -o .\bin\main -nostdlib -ffreestanding -fno-exceptions -nostartfiles -T .\src\sam3u2e.ld -mthumb -pedantic -Wall -std=c++17 -ggdb -Ofast
Если я удалю флаг -Ofast
и не буду использовать оптимизацию, я получаю следующую ошибку компоновщика: section .text._ZN4_PMCC2Ev LMA [0008019c,000801bf] overlaps section .data LMA [0008019c,0008019f]
Однако, если я включить его, он компилируется нормально, но когда я пытаюсь инициализировать такие структуры:
struct Example {
unsigned int const ID;
unsigned int volatile & some_register;
Example(unsigned int const id, unsigned int const register_address) : ID(id),
some_register(*((unsigned int volatile *)register_address)) {}
} instance(0x12345678, 0xDEADBEEF);
, я замечаю при разборке, что адрес instance.some_register
сохраняется в FLA SH, сразу после main()
, но похоже, что на него не ссылается какой-либо код, даже когда он пишет в него так:
instance.some_register = 1234;
Однако instance.ID
загружается из ОЗУ, но из адрес выше, чем размер .data
, что означает, что он никогда не копируется из FLA SH в RAM. Но если я изменю местоположение .bss
с > RAM
на > FLASH
, он попытается загрузить instance.ID
из FLA SH, чего я не понимаю, потому что идентификатор должен быть в .rodata
в любом случае.
Кроме того, я замечаю, что даже если я вообще не ссылаюсь на структуру в коде, кроме определения ее, что адрес все еще находится в FLA SH, мне интересно, можно ли было бы сказать компоновщик, чтобы не включать код для инициализированных структур, на которые нигде нет ссылок?
РЕДАКТИРОВАТЬ: Разделы компоновщика:
разделы компоновщика
, как вы можете видеть, раздел .data (который копируется в ОЗУ) имеет размер всего 4 байта. Однако сборка пытается загрузить instance.ID
и адрес instance.some_register
из ОЗУ --- это больше, чем 0x20000004, что меня смущает, потому что эти значения в любом случае должны быть доступны только для чтения и, следовательно, сохранены в fla sh?
РЕДАКТИРОВАТЬ 2: Я, вероятно, не достаточно ясно понял, что должен делать код. Я попытаюсь объяснить снова. Я хочу определить набор различных структур, каждая из которых будет иметь разные переменные. Каждая переменная ссылается на регистр устройства (путем установки указателя переменной на адрес соответствующего регистра). Поэтому, когда пользователь будет писать в эти регистры, например: peripheral.some_register = 123;
, значение будет записано в фактический физический регистр.
В скомпилированном (оптимизированном) коде я действительно не хочу, чтобы эти структуры существовали , поэтому ЦП не будет иметь дело с инициализацией данных, а вместо этого будет просто рассматривать их как набор указателей на разные периферийные регистры. Поскольку это будут данные только для чтения, они также могут быть расположены в FLA SH, и поэтому не потребуется использовать оперативную память.
Я предполагаю, что это означает, что я не должен использовать конструкторы, поскольку тогда это будет означать, что процессору потребуется их инициализировать, даже если данные, опять же, предназначены только для чтения. Пользователю также не нужно будет создавать свои собственные экземпляры структур, если это поможет с чем-либо.
Изначально я хотел использовать конструкторы, потому что есть некоторые периферийные устройства с более чем 50 регистрами каждое, которые имеют одинаковые смещения на периферийное устройство, но с разными базовыми адресами, поэтому я надеялся сэкономить немного времени, избавившись от необходимости копировать и вставлять один и тот же адрес для каждого регистра и добавлять к нему номер.