Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кармин Новиелло - Освоение STM32.pdf
Скачиваний:
2743
Добавлен:
23.09.2021
Размер:
47.68 Mб
Скачать

Организация памяти

521

нашего приложения (переопределяя символьное имя по умолчанию _start)10. Строки [12:28] определяют содержимое секций .text и .data. В секцию .text сначала будет помещена таблица векторов, а затем код программы. С помощью директивы ALIGN(4) мы говорим, что секция будет выровнена по словам (4 Байт), а директива >FLASH указывает, что секция .text будет помещена во Flash-память. KEEP(*(.isr_vector)) говорит компоновщику LD удерживать таблицу векторов в конечном абсолютном файле, иначе секция может быть «отброшена» другими инструментами, выполняющими оптимизацию конечного файла. Наконец, также определяется секция .data (несмотря на то что в данном примере она ничего не содержит), и она помещается в память SRAM.

Прежде чем мы сможем скомпилировать микропрограмму, нам нужно дать Eclipse команду включить в проект скрипт компоновщика во время компиляции. Зайдите в

Project settings → C/C++ Build → Settings. В разделе Cross ARM C Linker → General

добавьте запись ”../ldscript.ld” в список Script files (-T). Теперь вы можете скомпилировать микропрограмму и загрузить ее в свою Nucleo. Поздравляю: практически невозможно получить меньшее приложение для STM3211.

20.2.1. Исследование бинарного ELF-файла

Бинарный ELF-файл может быть исследован при помощи ряда инструментов, предоставляемых инструментарием GNU MCU. objdump и readelf являются наиболее распространенными. Описание их использования выходит за рамки данной книги. Тем не менее, настоятельно рекомендуется выделить пару часов на игру с их необязательными параметрами командной строке. Понимание того, как создается бинарный файл, может значительно улучшить знания о том, что находится «под капотом». Например, при запуске objdump с параметром -h отображается содержимое всех секций, содержащихся в бинарном файле микропрограммы12.

# ~/STM32Toolchain/gcc-arm/bin/arm-none-eabi-objdump -h nucleo-f401RE.elf

nucleo-f401RE.elf:

file format elf32-littlearm

 

Sections:

 

 

 

 

 

Idx Name

Size

VMA

LMA

File off

Algn

0

.text

00000008

08000000

08000000

00008000

2**2

 

 

CONTENTS, ALLOC, LOAD, READONLY, DATA

 

1

.text.main

00000040

08000008

08000008

00008008

2**2

 

 

CONTENTS, ALLOC, LOAD, READONLY, CODE

 

2

.text.delay

00000020

08000048

08000048

00008048

2**2

 

 

CONTENTS, ALLOC, LOAD, READONLY, CODE

 

3

.comment

00000070

00000000

00000000

0000b1d2

2**0

 

 

CONTENTS, READONLY

 

 

 

4

.ARM.attributes 00000033 00000000 00000000

0000b242 2**0

 

 

CONTENTS, READONLY

 

 

 

10Директива ENTRY() не имеет смысла во встроенных приложениях, где фактическая точка входа соответствует обработчику исключения сброса Reset. Тем не менее, она может быть информативной для отладчиков и симуляторов, и по этой причине вы найдете ее в официальных скриптах компоновщика LD.

11Ну ладно, написание кода на языке ассемблера позволит вам сэкономить дополнительное место, но данная книга не для мазохистов ;-D

12Когда вы запустите команду, то увидите гораздо больше секций, относящихся к отладке. Здесь вы их не увидите, потому что отладочная информация была «отброшена» из файла с помощью команды arm-none-

eabi-strip.

Организация памяти

522

Взглянув на приведенный выше вывод консоли, мы видим несколько моментов, касающихся секций, которые содержатся в бинарном файле. Каждая секция имеет размер, выраженный в байтах. Секция также имеет два адреса: виртуальный адрес памяти или ра-

бочий адрес (Virtual Memory Address, VMA) и загружаемый адрес памяти или адрес распо-

ложения (Load Memory Address, LMA). Во встраиваемых системах, таких как микроконтроллеры STM32, VMA – адрес, который будет иметь секция, когда начнется выполнение микропрограммы. LMA – адрес, в который будет загружена секция. В большинстве случаев эти два адреса будут одинаковыми. Как мы увидим в следующем параграфе, они различаются в случае секции .data.

Каждая секция имеет несколько атрибутов, которые сообщают загрузчику (например, в нашем случае загрузчиком является GDB в сочетании с OpenOCD или инструмент STM32CubeProgrammer), что делать с данной секцией. Давайте посмотрим, что они означают:

CONTENTS: этот атрибут сообщает загрузчику, что секция в бинарном файле содер-

жит данные для загрузки в адрес конечной памяти LMA. Как мы увидим далее, секция .bss не имеет содержимого в бинарном файле.

ALLOC: говорит о выделении соответствующего пространства в памяти LMA (кото-

рая может быть как Flash-памятью, так и памятью SRAM). Размер выделенного пространства задан в столбце Size.

LOAD: предписывает загрузить данные из секции, содержащейся в бинарном

файле, в конечную память LMA.

READONLY: сообщает, что содержимое секции доступно только для чтения.

CODE: сообщает, что содержимое секции является двоичным кодом.

Другой интересный момент, который следует отметить из предыдущего вывода консоли, заключается в том, что бинарный файл содержит отдельную секцию для каждого вызываемого объекта, содержащегося в исходном коде (.text.main для main() и

.text.delay для delay()). Мы должны указать компоновщику объединить все секции

.text в одну общую секцию, изменив скрипт компоновщика следующим образом:

.text : ALIGN(4)

 

 

{

 

 

*(.isr_vector)

/* Таблица векторов

*/

*(.text)

/* Код программы */

 

*(.text*)

/* Объединение всех

секций .text.* в секцию .text */

KEEP(*(.isr_vector)) } >FLASH

Как мы увидим позже, возможность иметь отдельные секции для каждого вызываемого объекта позволяет нам выборочно помещать некоторые функции в разные типы памяти (например, в быструю CCM-память некоторых микроконтроллеров STM32).

Наконец, в столбце File off задано смещение секции в бинарном файле, в то время как в столбце Algn задано выравнивание данных в памяти, которое составляет 4 Байт.