Линкер рассчитывает неправильные адреса для раздела родата

Я создал минимальный пример моей проблемы. В 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 ответа

В вашем скрипте компоновщика много странных вещей

  1. .rodata обычно находится в ROM

    .rodata : { *(.rodata) } > ROM
    
  2. .data находится в RAM, но данные копируются из ROM во время запуска:

    .data : { *(.data) } > ram AT > rom 
    
  3. Ваша локальная переменная buff не должна быть инициализирована из.rodata. Компилятор может оптимизировать его просто для хранения непосредственных значений из кода. Он может полностью оптимизировать его и встроить функцию тестирования. Существует много возможных оптимизаций, так как код очень тривиален. сделать бафф volatile а затем скомпилировать.

Я выяснил, что здесь происходит: в начале main значения, хранящиеся в RAM в.rodata, полностью копируются в стек. Поэтому указатель массива теперь указывает на стек, а не на.rodata. Это не оптимально, и мне, возможно, придется найти способ оптимизировать это и удалить лишние данные. Но в любом случае это должно работать. Я забыл инициализировать не только указатель стека, но и указатель кадра. И есть еще одна ошибка в моем оборудовании. Вот почему это не сработало. Спасибо за помощь!

Другие вопросы по тегам