Линкер вычисляет неправильные адреса для раздела родата - PullRequest
0 голосов
/ 06 сентября 2018

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

EDIT:

Мой ЦП имеет архитектуру havard и не может напрямую обращаться к данным из ПЗУ. Поэтому .rodata и .data должны быть в оперативной памяти. Мой подход заключается в том, что программный процесс записывает инструкции в ПЗУ, но также записывает .rodata и .data в ОЗУ. Моя реализация аппаратного обеспечения облегчает это. (Мой скрипт разделяет эти два блока данных двоичного файла и транскодирует его в протокол, который может обрабатывать мой программный модуль.)

И в двоичном на первый взгляд это работает: .text находится в адресном пространстве ПЗУ, а .rodata и .data - в адресном пространстве ОЗУ. Но адреса к .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 ]

0 голосов
/ 10 сентября 2018

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

0 голосов
/ 06 сентября 2018

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

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

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

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

...