Линкер рассчитывает неправильные адреса для раздела родата
Я создал минимальный пример моей проблемы. В c файле я инициализирую массив с 16 элементами. Затем я вызываю функцию с указателем массива и его размером в качестве параметра. Сама функция работает, я проверил это с помощью файла разборки. Также инициализация стека указателя работает нормально. Проблема в том, что параметр функции указателя массива неверен. Я проверил это, и причина сбоя находится в самом начале основного раздела. Здесь указатель хранится в стеке.
Что я не понимаю: значения массива хранятся в разделе.rodata. Этот раздел начинается с 0x1000. Таким образом, указатель на массив также должен быть 0x1000. При разборке 0x1000 загружается в a5 (правильное значение). Но затем он загружает значение адреса a5 в a4. Так что 0x1000 представляет указатель на указатель на массив, что не имеет смысла imho. Кто-нибудь знает, что я делаю не так?
Вот вся необходимая информация:
c программа:
void test(uint8_t *array, int size){
for(int i=0; i<size; ++i){
LED_ADDR = array[i];
}
}
int main(){
uint8_t buf[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
test(buf, 16);
}
скрипт компоновщика:
OUTPUT_ARCH( "riscv" )
ROMSIZE = 0x1000;
ROM_OFFSET = 0x0000;
RAMSIZE = 0x1000;
RAM_OFFSET = 0x1000;
/* provide variables for startup code (stack init) */
STACK_TOP = ( RAMSIZE + RAM_OFFSET - 4 );
ENTRY (start)
MEMORY {
rom (rx) : ORIGIN = ROM_OFFSET, LENGTH = ROMSIZE
ram (!rx) : ORIGIN = RAM_OFFSET, LENGTH = RAMSIZE
}
SECTIONS {
.reset : { <PROJECTPATH>/obj/startup.o } > rom /* startup code */
.text : { *(.text) } > rom /* executable data */
.rodata : { *(.rodata) } > ram /* read only data */
.sdata : { *(.sdata) } > ram /* init vars */
.bss (NOLOAD) : { *(.bss) FILL(0x0f); } > ram /* uninit data */
}
важные части файла дизассемблирования: -in .text, начало main(): указатель массива должен храниться в стеке, я полагаю:
80: 000017b7 lui a5,0x1 # a5 = first ram addr: begin of .rodata
84: 0007a703 lw a4,0(a5) # a4 = content of this addr?!?!?!
88: fee42023 sw a4,-32(s0) # a4 gets stored on stack
-.rodata, содержит значения массива:
Disassembly of section .rodata:
00001000 <.rodata>:
1000: 0100
1002: 0302
1004: 0504
...
100e: 0f0e
РЕДАКТИРОВАТЬ:
Мой ЦП имеет архитектуру havard и не может напрямую обращаться к данным из ПЗУ. Таким образом.rodata и.data должны быть в оперативной памяти. Мой подход заключается в том, что программный процесс записывает инструкции в ПЗУ, но также записывает.rodata и.data в ОЗУ. Моя реализация аппаратного обеспечения облегчает это. (Мой скрипт разделяет эти два блока данных двоичного файла и транскодирует его в протоколе, который может обрабатывать мой программный модуль.)
И в двоичном на первый взгляд это работает:.text находится в адресном пространстве ROM, а.rodata и.data - в адресном пространстве RAM. Но адреса к.rodata, по подсчетам компоновщика, неверны.
Моя программа предназначена только для проверки ее функциональности, в противном случае я бы не стал писать такой код. (Флаг оптимизации также -o0.)
Итак, прежде всего, я хотел бы понять строки в начале main(), которые должны поместить указатель массива в стек.
80: 000017b7 lui a5,0x1 # a5 = first ram addr: begin of .rodata
84: 0007a703 lw a4,0(a5) # a4 = content of this addr?!?!?!
88: fee42023 sw a4,-32(s0) # a4 gets stored on stack
Почему компоновщик рассматривает начало.rodata как указатель на массив, а не как реальный адрес массива?
2 ответа
В вашем скрипте компоновщика много странных вещей
.rodata обычно находится в ROM
.rodata : { *(.rodata) } > ROM
.data находится в RAM, но данные копируются из ROM во время запуска:
.data : { *(.data) } > ram AT > rom
Ваша локальная переменная buff не должна быть инициализирована из.rodata. Компилятор может оптимизировать его просто для хранения непосредственных значений из кода. Он может полностью оптимизировать его и встроить функцию тестирования. Существует много возможных оптимизаций, так как код очень тривиален. сделать бафф
volatile
а затем скомпилировать.
Я выяснил, что здесь происходит: в начале main значения, хранящиеся в RAM в.rodata, полностью копируются в стек. Поэтому указатель массива теперь указывает на стек, а не на.rodata. Это не оптимально, и мне, возможно, придется найти способ оптимизировать это и удалить лишние данные. Но в любом случае это должно работать. Я забыл инициализировать не только указатель стека, но и указатель кадра. И есть еще одна ошибка в моем оборудовании. Вот почему это не сработало. Спасибо за помощь!