ЛР14. Обновление скрипта компоновщика и стартап-файла

This commit is contained in:
Andrei Solodovnikov
2024-07-29 16:06:47 +03:00
parent dfee5efcec
commit 59510a522b
3 changed files with 47 additions and 34 deletions

View File

@@ -103,17 +103,6 @@ _Таблица 1. Ассемблерные мнемоники для целоч
Все это с подробными комментариями описано в файле `linker_script.ld`. Все это с подробными комментариями описано в файле `linker_script.ld`.
```ld ```ld
/* -----------------------------------------------------------------------------
* Project Name : Architectures of Processor Systems (APS) lab work
* Organization : National Research University of Electronic Technology (MIET)
* Department : Institute of Microdevices and Control Systems
* Author(s) : Andrei Solodovnikov
* Email(s) : hepoh@org.miet.ru
See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
* ------------------------------------------------------------------------------
*/
OUTPUT_FORMAT("elf32-littleriscv") /* Указываем порядок следования байт */ OUTPUT_FORMAT("elf32-littleriscv") /* Указываем порядок следования байт */
ENTRY(_start) /* мы сообщаем компоновщику, что первая ENTRY(_start) /* мы сообщаем компоновщику, что первая
@@ -144,8 +133,8 @@ _trap_stack_size = 640; /* Размер стека обработ
_stack_size = 640; /* Размер программного стека. _stack_size = 640; /* Размер программного стека.
Данный размер позволяет выполнить Данный размер позволяет выполнить
до 8 вложенных вызовов. от 8 вложенных вызовов.
*/ */
/* /*
В данном разделе описывается размещение программы в памяти. В данном разделе описывается размещение программы в памяти.
@@ -188,11 +177,22 @@ SECTIONS
*(.text*) *(.text*)
} > instr_mem } > instr_mem
В скобках после оператора AT указывается Load Memory Address (LMA). Чтобы
адреса памяти инструкций и памяти данных при компоновке не пересекались, мы /*
будем использовать заведомо несуществующий LMA, который в последствии будем Секция данных размещается аналогично секции инструкций за исключением
игнорировать. адреса загрузки в памяти (Load Memory Address, LMA). Поскольку память
.data : AT (0x80000000) { инструкций и данных физически разделены, у них есть пересекающееся адресное
пространство, которое мы бы хотели использовать (поэтому в разделе MEMORY мы
указали что стартовые адреса обоих памятей равны нулю). Однако компоновщику
это не нравится, ведь как он будет размещать две разные секции в одно и то же
место. Поэтому мы ему сообщаем, с помощью оператора "AT", что загружать секцию
данных нужно на самом деле не по нулевому адресу, а по какому-то другому,
заведомо большему чем размер памяти инструкций, но процессор будет
использовать адреса, начинающиеся с нуля. Такой вариант компоновщика
устраивает и он собирает исполняемый файл без ошибок. Наша же задача,
загрузить итоговую секцию данных по нулевым адресам памяти данных.
*/
.data : AT (0x00800000) {
/* /*
Общепринято присваивать GP значение равное началу секции данных, смещенное Общепринято присваивать GP значение равное началу секции данных, смещенное
на 2048 байт вперед. на 2048 байт вперед.
@@ -206,6 +206,7 @@ SECTIONS
*/ */
_gbl_ptr = . + 2048; _gbl_ptr = . + 2048;
*(.*data*) *(.*data*)
*(.sdata*)
} > data_mem } > data_mem
@@ -242,12 +243,12 @@ SECTIONS
Дополнительно мы указываем, что данная секция должна быть размещена в Дополнительно мы указываем, что данная секция должна быть размещена в
регионе "data_mem". регионе "data_mem".
*/ */
_bss_start = .;
.bss : { .bss : {
_bss_start = .; *(.bss*)
*bss* *(.sbss*)
*(COMMON)
_bss_end = .;
} > data_mem } > data_mem
_bss_end = .;
/*================================= /*=================================

View File

@@ -39,8 +39,8 @@ _trap_stack_size = 640; /* Размер стека обработ
_stack_size = 640; /* Размер программного стека. _stack_size = 640; /* Размер программного стека.
Данный размер позволяет выполнить Данный размер позволяет выполнить
до 8 вложенных вызовов. от 8 вложенных вызовов.
*/ */
/* /*
В данном разделе описывается размещение программы в памяти. В данном разделе описывается размещение программы в памяти.
@@ -83,11 +83,22 @@ SECTIONS
*(.text*) *(.text*)
} > instr_mem } > instr_mem
В скобках после оператора AT указывается Load Memory Address (LMA). Чтобы
адреса памяти инструкций и памяти данных при компоновке не пересекались, мы /*
будем использовать заведомо несуществующий LMA, который в последствии будем Секция данных размещается аналогично секции инструкций за исключением
игнорировать. адреса загрузки в памяти (Load Memory Address, LMA). Поскольку память
.data : AT (0x80000000) { инструкций и данных физически разделены, у них есть пересекающееся адресное
пространство, которое мы бы хотели использовать (поэтому в разделе MEMORY мы
указали что стартовые адреса обоих памятей равны нулю). Однако компоновщику
это не нравится, ведь как он будет размещать две разные секции в одно и то же
место. Поэтому мы ему сообщаем, с помощью оператора "AT", что загружать секцию
данных нужно на самом деле не по нулевому адресу, а по какому-то другому,
заведомо большему чем размер памяти инструкций, но процессор будет
использовать адреса, начинающиеся с нуля. Такой вариант компоновщика
устраивает и он собирает исполняемый файл без ошибок. Наша же задача,
загрузить итоговую секцию данных по нулевым адресам памяти данных.
*/
.data : AT (0x00800000) {
/* /*
Общепринято присваивать GP значение равное началу секции данных, смещенное Общепринято присваивать GP значение равное началу секции данных, смещенное
на 2048 байт вперед. на 2048 байт вперед.
@@ -101,6 +112,7 @@ SECTIONS
*/ */
_gbl_ptr = . + 2048; _gbl_ptr = . + 2048;
*(.*data*) *(.*data*)
*(.sdata*)
} > data_mem } > data_mem
@@ -137,12 +149,12 @@ SECTIONS
Дополнительно мы указываем, что данная секция должна быть размещена в Дополнительно мы указываем, что данная секция должна быть размещена в
регионе "data_mem". регионе "data_mem".
*/ */
_bss_start = .;
.bss : { .bss : {
_bss_start = .; *(.bss*)
*bss* *(.sbss*)
*(COMMON)
_bss_end = .;
} > data_mem } > data_mem
_bss_end = .;
/*================================= /*=================================

View File

@@ -31,8 +31,8 @@ _irq_config:
li t1, -1 # -1 (все биты равны 1) означает, что разрешены все прерывания li t1, -1 # -1 (все биты равны 1) означает, что разрешены все прерывания
la t2, _trap_stack_ptr la t2, _trap_stack_ptr
csrw mtvec, t0 csrw mtvec, t0
csrw mie, t1
csrw mscratch, t2 csrw mscratch, t2
csrw mie, t1
# Вызов функции main # Вызов функции main
_main_call: _main_call: