-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Overlay - способ размещения программ, позволяющий занимать меньше оперативной памяти.
Способ заключается в разделении программы на отдельные независимые блоки - оверлеи, которые поочерёдно записываются и исполняются из одной и той же области ОЗУ - overlay-области.
Механизм оверлеев как правило используется в embedded системах. В современных ПK используется механизм виртуализации памяти.
В embedded системах использование оверлеев - это наиболее правильный способ организации проекта, размер которого превышает размер ОЗУ и единственный способ иметь возможность отладки для такого проекта.
- Оглавление
- Quick start
- Виртуальная и физическая память
- Overlay и linker
- Overlay и GDB
- Исправления в исходниках GDB
- GDB-режимы работы с оверлеями
- Дополнительные средства по работе с оверлеями
- Примечание
- Сборка GDB
- Проект riscv-overlay
- Ссылки
Для использования оверлеев и для поддержки отладчиком GDB оверлеев необходимо:
- Конструкция OVERLAY:{...} в linker-скрипте - выделении overlay-области.
- Таблица
_ovly_table
и константа_novlys
- должны быть определены в linker-скрипте и объявлены в целевой программе. - Overlay-manager - часть целевой программы для управления загрузкой оверлеев в runtime.
- Функция
_ovly_debug_event()
- должна быть определена в целевой программе и вызываться в оверлей-менеджере, нужна для работы breakpoint-ов внутри оверлеев. - В начале debug-сессии выполнить GDB-команду
overlay auto
- включение автоматического режима отладки оверлеев. - Можно использовать дополнительные средства по работе с оверлеями.
Проект overlay_demo - это демонстрационный пример, он содержит всё необходимое для работы с оверлеями. Эти наработки могут быть использованы в полноценном штатном проекте.
LMA(load memory address) - область хранения, ROM (ПЗУ).
VMA(virtual memory address) - область выполнения, RAM (ОЗУ).
При инициализации код копируется из LMA в VMA и выполняется в VMA.
Таким образом каждый символ имеет два адреса: LMA и VMA, по умолчанию они равны.
Для каждой секции дополнительно можно указать адрес загрузки в LMA, тогда адреса LMA и VMA будут отличаться.
Пример задания адреса LMA в linker-скрипте:
.sect : AT(адрес_LMA)
{
...
}
или
.sect :
{
...
} AT > регион_LMA
Посмотреть адреса LMA и VMA: .../riscv64-unknown-elf-objdump -h файл.elf
Обычно LMA и VMA равны, но у overlay-секций они разные.
Overlay (перекрывание) - простой способ описать секции, которые загружены, как часть единого образа памяти, но исполняются с одного и того же адреса.
В runtime overlay manager будет копировать наложенные секции в и из runtime адрес, как требуется, возможно просто манипуляциями с битами адреса. Это может быть удобно, например, если определенный регион памяти быстрее, чем остальные.
Конструкция OVERLAY используется внутри конструкции SECTION, как описание output-секции.
OVERLAY [start ] : [NOCROSSREFS] [AT ( ldaddr )]
{
secname1
{
output-section-command
output-section-command
...
} [:phdr ...] [=fill ]
secname2
{
output-section-command
output-section-command
...
} [:phdr ...] [=fill ]
...
} [>region ] [:phdr ...] [=fill ] [,]
Объявление overlay-секций - такое же, как и основная конструкция SECTION, за исключением того, что нельзя указывать адреса и нельзя указывать регионы для секций внутри конструкции OVERLAY.
Запятая в конце необходима, если используется fill и следующая section-команда выглядит как продолжение выражения.
Секции внутри Overlay имеют одинаковый стартовый адрес. Адреса загрузки секций расположены, так если бы они находились в памяти последовательно, начиная с адреса загрузки всего overlay (при нормальном объявлении секций адрес загрузки опционален).
Если используется ключевое слово NOCROSSREFS, то ссылки между секциями будут считаться ошибками линковки, поэтому NOCROSSREFS лучше использовать!
Для каждой overlay-секции автоматически определены два символа '__load_start_secname' (start LMA) и '__load_end_secname' (end LMA).
В конце overlay счётчик позиции устанавливается в начальный адрес overlay + размер наибольшей секции.
SECTIONS
{
...
OVERLAY 0x1000 : AT (0x4000)
{
.text0 { o1/*.o(.text) }
.text1 { o2/*.o(.text) }
}
...
}
Маппирование overlay-секции в overlay-область (обращение по имени: по символам):
extern char __load_start_text1, __load_stop_text1;
memcpy ((char *) 0x1000, &__load_start_text1, &__load_stop_text1 - &__load_start_text1);
14.1. How Overlays Work
Загрузкой оверлеев управляет overlay manager, это часть целевой программы, работает в runtime.
В overlay содержаться модули, которые будут вызываться из основной программы. Расположение в памяти: сначала располагается основная программа, затем overlay-область. Рядом с основной программой должно быть выделено достаточно места, чтобы туда мог поместиться наибольший overlay.
Теперь, чтобы вызвать функцию, находящуюся в overlay, нужно скопировать этот overlay в RAM, и перейти в его entry point.
Overlay, загруженный в RAM память и готовый к использованию называется mapped overlay (VMA, адрес RAM). Не загруженный overlay называется unmapped overlay, он хранится в load адресе (в ROM). Mapped address - это VMA. Unmapped address (load address) - это LMA.
При использовании overlay есть ограничения:
- Перед тем как вызывать или возвращаться в оверлейную функцию, программа должна убедиться, что оверлей маппирован. Иначе call или return передаст управление по правильному адресу, но из-за неправильного оверлея программа вероятно слетит.
- Процесс маппирования дорогой для системы. Оверлеи следует выбирать тщательно, чтобы минимизировать эффект для производительности.
- Elf должен содержать все оверлей-инструкции, появляющиеся в load адресе, а не mapped адресе. Однако оверлейные инструкции могут быть релоцированы и их символы определены, как если бы оверлей находился в mapped адресе. Нужно использовать ld-скрипт, чтобы задать различные load и relocation адреса для частей программы.
- Должна быть возможность загрузки elf в большие адреса адресного пространства.
- Если оверлеи достаточно малы, то можно выделять несколько оверлеев за раз. И иметь несколько маппированных оверлеев одновременно.
- Можно использовать оверлеи и для данных и для инструкций. Обычно использование data-оверлеев менее прозрачно, чем использование code-оверлеев: code-оверлей необходим когда делается вызов или возврат в функцию, а data-оверлей требуется всё время использования данных. Также, если изменяется содержимое data-оверлея в ОЗУ, то необходимо скопировать содержимое оверлея обратно в load адрес (в ПЗУ) перед тем как в текущую оверлей-область будет загружен другой оверлей.
14.2 Overlay Commands
Чтобы использовать GDB с оверлеями, каждый оверлей должен соответствовать отдельной секции. Адреса секции (VMA и LMA) должны быть адресами оверлея: mapped и load соответственно. Отождествление оверлеев с секциями позволяет GDB определить соответствующий адрес функции или переменной в зависимости от того маппирован оверлей или нет.
GDB оверлейные команды: overlay ... (сокращенно ov, ovly).
Некоторые GDB-команды по работе с оверлеями:
- overlay manual - Включение ручного режима отладки оверлеев.
- overlay auto - Включение автоматического режима отладки оверлеев. В этом режиме GDB учитывает таблицу
_ovly_table
, чтобы понять, какие оверлеи mapped. - overlay list - Отображение оверлеев, которые mapped на данный момент. В том числе их mapped адрес и load адрес.
- overlay load - Загрузить (обновить) таблицу
_ovly_table
из цели в GDB-клиент. Обычно таблица обновляется каждый раз, когда цель останавливается. Команда необходима, если пользователь сам меняет таблицу с помощью средств GDB. Команда может быть полезна в automatic overlay режиме. - overlay map ovlyname - Указать вручную, какой оверлей сейчас mapped. Пример: overlay map .ovly0
Когда включен режим отладки оверлеев, GDB распознаёт код из unmapped оверлеев и выводит имя unmapped функции в звёздочках:
(gdb) overlay list
No sections are mapped.
(gdb) print foo
$5 = {int (int)} 0x100000 <*foo*>
Когда оверлей mapped, GDB выводит имя функции нормально:
(gdb) overlay list
Section .ov.foo.text, loaded at 0x100000 - 0x100034,
mapped at 0x1016 - 0x104a
(gdb) print foo
$6 = {int (int)} 0x1016 <foo>
Когда включен режим отладки оверлеев, GDB может находить текущий адрес для оверлейных функций и переменных и когда оверлей mapped и когда unmapped. Также будут работать gdb-команды такие как break и disassemble даже в unmapped коде.
14.3 Automatic Overlay Debugging
GDB может автоматически отслеживать какие оверлеи mapped а какие unmapped, используя простую кооперацию с overlay manager. Если включен режим автоматической отладки оверлеев (команда overlay auto), то GDB, смотрит память на предмет конкретных переменных, описывающих текущее состояние оверлея. Эти переменные должны быть определены в overlay manager для педдержки GDB режима автоматической отладки оверлеев.
Этот массив структур лучше и проще определять в ld-скрипте.
_ovly_table
- массив структур:
struct
{
unsigned long vma;
unsigned long size;
unsigned long lma;
unsigned long mapped;
}
_novlys
: 4-байтовый знаковый int. Общее количество элементов в _ovly_table
.
Чтобы решить, является ли конкретный оверлей mapped или нет, GDB анализирует соответствующий элемент таблицы _ovly_table
, чьи поля 'vma' и 'lma' равны VMA и LMA оверлейной секции в elf. Когда GDB находит соответствующий элемент, GDB опрашивает его поле 'mapped', чтобы определить является ли данный оверлей mapped на текущий момент.
Дополнительно, в overlay manager может быть определена функция _ovly_debug_event
. Если эта функция определена, GDB тихо поставит breakpoint на неё. Если overlay manager затем вызывает эту функцию каждый раз когда он меняет overlay table, то это позволит GDB точно отслеживать какие именно оверлеи находятся в памяти программ, и обновлять breakpoint-ы установленные в оверлеи (в том числе в unmapped оверлеи). Это позволяет breakpoint-ам работать даже если оверлеи находятся в ROM или в другой непереписываемой памяти, пока они не могут быть исполнены.
14.4. Overlay Sample Program
Пример работы с оверлеями есть в исходниках GDB '/gdb/testsuite/gdb.base'. В частности: overlays.c, ovlymgr.c, m32r.ld.
Комментарии из исходников GDB (.../gdb/symfile.c)Полезные GDB-команды
OVERLAYS:
Целевая модель выглядит следующим образом:
- Компоновщик позволяет маппировать (разместить) несколько секций в один и тот же VMA, каждую со своим собственным уникальным LMA.
- Предполагается, что существует некоторый runtime механизм для маппирования секций, одну за другой, из load адреса в VMA адрес.
- Этот код предоставляет механизм для GDB для отслеживания того, какие секции должны рассматриваться для маппирования. Эта информация используется для поиска символов и чтения/записи в память. Например, если секция была маппирована, то её содержимое должно быть считано из VMA, в противном случае из LMA.
Существует два уровня поддержки отладчиком оверлеев. Один из них - "ручной", в котором отладчик полагается на пользователя, который должен сообщить ему, какие overlay маппированы в данный момент. Этот уровень поддержки полностью реализован в ядре отладчика, а информация о том, маппирован ли overlay, хранится в таблице objfile->obj_section.
Второй уровень поддержки является "автоматическим" и доступен только в том случае, если цель-специфичный код предоставляет функциональность для чтения таблицы _ovly_table
(которая находится в памяти цели) и преобразования ее содержимого для отладчика (путем обновления состояний маппирования в таблицах obj_section).
Target Overlays for the "Simplest" overlay manager:
simple_overlay_update(...) - это дефолтный обработчик оверлеев. Он работает с минимальным overlay-менеджером, приведённом в примере. Точка входа - через указатель на функцию: gdbarch->overlay_update = simple_overlay_update. Цели, использующие другой overlay-менеджер, могут заменить указатель gdbarch->overlay_update на указатель на свою собственную функцию overlay_update.
gdbarch->overlay_update просматривает _ovly_table
, чтобы определить, какие overlay маппированы, и обновляет информацию в GDB.
gdbarch->overlay_update(...) вызывается в gdbarch_overlay_update(...) в gdbarch.c.
Чтобы обновить информацию о состоянии маппорования в GDB, сохраняется кэшированная копию целевой _ovly_table
и делаются попытки определить, когда кэшированная копия становится недействительной. Основной точкой входа является "simple_overlay_update(SECT)", которая ищет SECT в кэшированной таблице и повторно считывает из цели только запись для этой секции (когда это возможно).
Для корректной работы GDB с оверлеями необходимо внести исправления в исходники GDB (и сделать собственную сборку GDB):
1. Проинициализировать указатель gdbarch->overlay_update
:
Структура gdbarch описывает архитектуру конкретного GDB-клиента.
Посмотреть текущее соcтояние gdbarch можно с помощью GDB-команды 'maint print architecture'. Часть вывода GDB-команды 'maint print architecture', относящаяся к оверлеям:
gdbarch_dump: gdbarch_overlay_update_p() = 1
gdbarch_dump: overlay_update = <0x6a3ef0>
gdbarch_overlay_update_p(struct gdbarch *gdbarch)
- Это просто признак того, что overlay_update задан, то есть, что gdbarch->overlay_update != NULL
.
gdbarch->overlay_update
- это указатель на функцию simple_overlay_update(struct obj_section *osect)
, которая считывает и анализирует таблицу _ovly_table
из памяти цели. Вызов по указетелю gdbarch->overlay_update
делается внутри функции gdbarch_overlay_update(struct gdbarch *gdbarch, gdbarch_overlay_update_ftype overlay_update)
в gdbarch.c. То есть функция gdbarch_overlay_update(...)
это просто обёртка над вызовом по указетелю gdbarch->overlay_update
. Функция gdbarch_overlay_update(...)
вызывается в symfile.c, в том числе по GDB-команде 'overlay load' - overlay_load_command(...)
.
Но изначально надо проинициализировать gdbarch->overlay_update
указателем на функцию simple_overlay_update(struct obj_section *osect)
, которая определена в symfile.c. Это делается функцией set_gdbarch_overlay_update (struct gdbarch *gdbarch, gdbarch_overlay_update_ftype overlay_update)
, которая определена в gdbarch.c. Надо в riscv-tdep.c в конце определения riscv_gdbarch_init(...)
вызвать set_gdbarch_overlay_update(gdbarch, simple_overlay_update)
- по аналогии с m32r-tdep.c.
Эта инициализация указателя gdbarch->overlay_update
не была сделана для RISC-V - в riscv-tdep.c!
2. Поправить вывод overlay-команд:
У GDB-команд 'overlay auto', 'overlay manual', 'overlay off' некорректно выводятся сообщения.
В symfile.c в функциях overlay_auto_command(...)
, overlay_manual_command(...)
, overlay_off_command(...)
в выводе printf_filtered(_("..."));
нет '\n' в конце строки, из-за этого вывод этих GDB-команд работает некорректно (склеивается с выводом следующей команды). Эти сообщения выводятся только с 'set verbose on'.
Неправильно (склеиваются):
(gdb) set verbose on
(gdb) overlay auto
<ничего>
(gdb) overlay list
Automatic overlay debugging enabled.No sections are mapped.
Поправлено (добавлено '\n'):
(gdb) set verbose on
(gdb) overlay auto
Automatic overlay debugging enabled.
(gdb) overlay list
No sections are mapped.
(Версия GDB-клиента: 10.1)
Автоматический режим отладки оверлеев:
Автоматический режим (gdb-команда 'overlay auto') работает, если подправить исходники GDB-клиента (проинициализировать gdbarch->overlay_update
). То есть работает в собственной сборке GDB-клиента:
(gdb) set verbose on
(gdb) overlay auto
Automatic overlay debugging enabled.
...
(gdb) print/x *_ovly_table@2
$1 = {{0x10000060, 0x44, 0x10080400, 0x0}, {0x10000060, 0x18c, 0x10080444, 0x1}}
(gdb) overlay list
Section .ovly1, loaded at 0x10080444 - 0x100805d0, mapped at 0x10000060 - 0x100001ec
Когда gdbarch->overlay_update
не был проинициализирован (сборка toolchain: riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14), то автоматический режим не работал. Оверлеи, у которых _ovly_table.mapped == 1
, не помечались в GDB-клиенте как маппированные:
(gdb) overlay list
No sections are mapped.
Обновить состояние оверлеев не получалось:
(gdb) overlay load
This target does not know how to read its overlay state.
Функция _ovly_debug_event()
:
_ovly_debug_event()
вызывается в оверлей-менеджере и нужна для установки и сохранения брейкпоинтов в немаппированный код. В С++ коде должна быть объявлена как extern "C". Работает в режиме 'overlay auto' (в собственной сборке GDB-клиента).
Ручной режим:
Ручной режим включается gdb-командой 'overlay manual' (но можно использовать и 'overlay auto'), после этого можно использовать gdb-команду 'overlay map ...'.
Ручной режим работает:
(gdb) overlay map .ovly0
(gdb) overlay list
Section .ovly0, loaded at 0x10080400 - 0x10080444, mapped at 0x10000068 - 0x100000ac
Но при этом отладка внутри оверлей-функций иногда работает коряво.
(Реализованы с помощью Python-GDB-API)
Имитация overlay-менеджера с помощью Python-GDB-API:
Overlay-менеджер в embedded-программе загружает нужную overlay-секцию из ПЗУ в ОЗУ. Имитация overlay-менеджера с помощью Python-GDB-API скрипта загружает нужную overlay-секцию из elf (в хосте) в ОЗУ целевой машины. Такой подход позволяет использовать embedded систему даже в случае, если ПЗУ отсутствует (в том числе при использовании симулятора).
Теоретически обращаться к оверлеям можно по имени (overlay-секции) и по номеру (в _ovly_table
). Но символы __load_start_secname
и __load_end_secname
недоступны из GDB, и непонятно, есть ли они реально в elf. Остается вариант обращаться по номеру (и он проще).
Работа с оверлеями с помощью Python-GDB-API:
Реализовано как собственные GDB-команды gdb.Command.
Режим замены (перешагивания) штатного overlay-менеджера - GDB-команда 'ovreplace ovlymgr_name' - класс ReplaceOverlayManager(gdb.Command):
- Передача имени штатного overlay-менеджера и установка на него breakpoint
При останове на этом breakpoint:
* Загрузка overlay-секции из elf
* Обновление поля MAPPED в `_ovly_table` в ОЗУ
* Перешагивание тела штатного overlay-менеджера (не в самый конец)
Загрузка overlay-секции вручную - GDB-команда 'ovload ovlyno' - класс OverlayLoadManually(gdb.Command):
- Загрузка overlay-секции из elf
- Обновление поля MAPPED в `_ovly_table` в ОЗУ
Чтение и анализ _ovly_table
- GDB-команда 'getmapped' - класс GetNumMappedOverlay(gdb.Command):
- Чтение и анализ таблицы `_ovly_table` из ОЗУ
- Вывод номеров маппированных оверлеев или сообщения о том, что маппированных оверлеев нет
Реализация перешагивания тела штатного overlay-менеджера:
Возможно можно было бы использовать GDB-команду 'return retval', но перешагнуть надо не в самый конец overlay-менеджера, а на метку до вызова FlushCache()
и _ovly_debug_event()
.
Была идея реализовать свой класс, унаследованный от gdb.Breakpoint и переопределить в нём метод .stop(), который исполняется при срабатывании breakpoint. Но оказалось, что внутри самого метода .stop() цель ещё не находится в остановленном состоянии, и поэтому писать в память и выполнить GDB-команду 'jump ...' невозможно. Цель останавливается только при выходе из .stop() со значением True (при выходе с False - не останавливается). Поэтому после этого была попытка вызвать .stop() внутри самого .stop(), чтобы получилось, что первый возврат из .stop() был с True, а второй возврат - с False. Но оказалось, что каждый .stop() вызывается независимо от return status предыдущего, то есть в любом случае. Так что вариант с использованием .stop() не работает.
В итоге, для реализации перешагивания был использован механизм Events. На начале overlay-менеджера должен стоять Breakpoint. Нужно зарегистрировать обработчик события: 'gdb.events.stop.connect(stop_event_handler)'. При срабатывании breakpoint возникает событие events.stop. Внутри обработчика цель находится в остановленном состоянии и можно писать в память и выполнить gdb-команду 'jump ...'.
Подобным образом можно перешагивать любой код, например тело драйвера.
Важно:
В linker-скрипте может быть несколько overlay-областей OVERLAY:{...}. Но при этом таблица _ovly_table
всегда одна. Каждая overlay-область OVERLAY:{...} содержит несколько выходная overlay-секций (.ovly0; .ovly1 и т.д.). Каждая такая выходная overlay-секция может содержать одну или несколько входных секций (.text .data и т.д.). В overlay-секции могут содержаться входные секции разных объектников. Пример: .ovly0 { *foo.o(.text .text.* .data .data.* .sdata .sdata.*) *bar.o(.text .text.* .data .data.* .sdata .sdata.*) }
.
И для Си и для С++ выходные секции нужно указывать так: .ovly0 { *foobar.o(.text .text.* .data .data.* .sdata .sdata.*) }
. То есть указывать не только .text
; .data
; .sdata
но и .text.*
; .data.*
; .sdata.*
и т.д.
Важно:
Код из overlay-секции не может и не должен вызывать (использовать) код (и данные) из другой overlay-секции. Overlay-секция не должна иметь ссылки на другие overlay-секции: в ld-скрипте нужно использовать NOCROSSREFS.
Важно:
В overlay-менеджере, после загрузки очередного оверлея в ОЗУ нужно очистить кеш инструкций. В RISC-V это инструкция 'fence.i'.
Важно:
Размер _novlys
и _ovly_table
:
Функция symfile.c:simple_read_overlay_table() вызывается из symfile.c:simple_overlay_update(...), которая вызывается по указателю gdbarch->overlay_update из gdbarch.c:gdbarch_overlay_update(...), которая вызывается из symfile.c:overlay_load_command(...)(== GDB-команда 'overlay load') и из symfile.c:section_is_mapped(...).
Функция symfile.c:simple_read_overlay_table():
Размер _novlys
= 4 byte = 32 bit. Всегда.
Размер одного элемента таблицы _ovly_table
= word_size = gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT = gdbarch->long_bit / 8 = 64 / 8.
То есть word_size = размер типа long, который в данной gdbarch равен 64 bit.
Из вывода GDB-команды 'maint print architecture':
gdbarch_dump: long_bit = 64
Полезные GDB-команды:
- section sec_name addr - Замена адреса секции переданного elf на addr.
- maint info sections - Полная информация о секциях.
- maint info sections section-flags - Информация только о секциях, у которых section-flag = true. Флаг LOAD - секция загружена в память.
- info files - Информация из elf, в том числе адреса секций. Тоже самое, что команда info target.
- set verbose on - Подробный вывод, в том числе для оверлейных GDB-команд.
- set debug arch 2 - Отображение отладочных сообщений из gdbarch.
Обращение к overlay-секции по имени:
Если использовать конструкцию OVERLAY:{...}, то для каждой overlay-секции линкер автоматически формирует символы __load_start_secname
(start LMA) и __load_end_secname
(end LMA). Эти символы можно использовать в C/C++ коде. Но если они не используются в коде (к ним нет обращения), то их нет - компилятор их выкидывает, и, соответственно, из GDB они недоступны, в том числе и из py-gdb-api: gdb.lookup_global_symbol(__load_start_ovly0)
. Использование в C/C++ коде extern unsigned __load_start_ovly0 __attribute__((used));
не помогает.
Загрузка overlay-секций отладчиком при старте:
GDB-команда 'load' загружает из elf все секции (имеющие флаг load) в ОЗУ, в их LMA. Но что будет, если в проекте много оверлеев, и, соответственно есть большие load-адреса, которые больше, чем размер ОЗУ? Что будет, когда GDB-команда load попытается загрузить overlay-секции в такие адреса (адреса, которых нет в ОЗУ)? При исполнении программы с загрузкой из ПЗУ (без участия отладчика) - это не проблема, так как в этом случае overlay-менеджер в runtime загружает только нужный overlay в нужное время и место, а не все подряд.
Видимо, нужно иметь какую-то возможность не загружать отладчиком overlay-секции, но возможно ли это? Возможно стоит реализовать свою GDB-команду (вместо GDB-команды 'load'), которая бы загружала в ОЗУ из elf секции с load-флагом, кроме overlay-секций (у которых VMA != LMA).
В linker-скрипте секции можно указать тип NOLOAD, тогда секция будет помечена как 'not loadable' и не будет загружаться при старте. Но это не работает для конструкций OVERLAY:{...}.
Существует GDB-команда flash-erase - очищение flash регионов памяти. Непонятно как это работает и что должно получиться, выводится сообщение 'No flash memory regions found.'.
Сборка только GDB, не всего toolchain Собирать на Ubuntu
(по дефолту сборка делается без TUI)
Установить пакеты:
$ sudo apt-get install cmake autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf patchutils bc zlib1g-dev libexpat-dev libtool pkg-config mingw-w64 mingw-w64-tools texlive zip python-dev gettext libglib2.0-dev libpixman-1-dev swig ninja-build python3 python3-pip
$ sudo pip3 install meson
Склонировать:
$ git clone git@github.com:sifive/freedom-gdb-metal.git
$ cd freedom-gdb-metal
$ git submodule update --init --recursive
Запустить сборку (по дефолту сборка делается без TUI):
$ make clean
$ make package -j $(nproc)
Результат сборки - готовые архивы для Linux, Windows и др. будут в .../freedom-gdb-metal/bin/
Установить дополнительные пакеты:
$sudo apt-get install libncurses5-dev libncursesw5-dev
Изменить файлы: Makefile и .../freedom-gdb-metal/scripts/dyn-lib-check-x86_64-linux-ubuntu14.tcl
Makefile:
В Makefile есть две конфигурации сборки GDB-клиента - с поддержкой Py-GDB-API (с суффиксом "-py") и без поддержки. Нужно в обе эти конфигурации добавить "--enable-tui=yes " (можно добавить например после "--with-guile=no ").
.../freedom-gdb-metal/scripts/dyn-lib-check-x86_64-linux-ubuntu14.tcl:
В "set dllist [...]" добавить:
"libncursesw.so" \
"libtinfo.so" \
Иначе будет ошибка "Illegal libray used: ...":
Checking dynamic library usage for: .../freedom-gdb-metal/obj/x86_64-linux-ubuntu14/install/riscv64-unknown-elf-gdb-10.1.0-2020.12.8-x86_64-linux-ubuntu14/bin/riscv64-unknown-elf-gdb
Illegal library used: libncursesw.so.5 => /lib/x86_64-linux-gnu/libncursesw.so.5 (0x00007ff4d3ee0000)
Illegal library used: libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007ff4d3cb7000)
Запустить сборку с TUI:
$ make clean
$ make package -j $(nproc)
Для Linux (Ubuntu) с TUI собралось - есть соответствующий архив в .../freedom-gdb-metal/bin/
Но с для Windows с TUI не собралось:
Проблема с ncurses. Ошибка: "configure: error: no enhanced curses library found; disable TUI":
.../freedom-gdb-metal/obj/x86_64-w64-mingw32/buildlog/riscv64-unknown-elf-gdb/build-gdb-make-build.log:
configure: error: no enhanced curses library found; disable TUI
Makefile:10047: ошибка выполнения рецепта для цели «configure-gdb»
make[2]: *** [configure-gdb] Ошибка 1
make[2]: выход из каталога «.../freedom-gdb-metal/obj/x86_64-w64-mingw32/build/riscv64-unknown-elf-gdb/build-gdb»
Makefile:865: ошибка выполнения рецепта для цели «all»
make[1]: *** [all] Ошибка 2
make[1]: выход из каталога «.../freedom-gdb-metal/obj/x86_64-w64-mingw32/build/riscv64-unknown-elf-gdb/build-gdb»
Делается специально, чтобы упростить embedded разработку.
Overlay-функции хранятся в группах по 512B-4K. При объявлении overlay-функции и overlay-данных в C/C++ программе используется __attribute__((overlay_call))
и __attribute__((overlay_data))
. При вызове overlay-функции, компилятором генерируется определённый код.
Runtime-часть называется RT-Engine (видимо в том числе и overlay-manager). Address Token - это описатель, предоставляющий RT-Engine всю необходимую информацию для загрузки и вызова overlay-функции.
Планируется в компилятор, линковщик и binutils добавить поддержку таких оверлеев. В том числе реализовать свой ABI, где часть регистров будет использоваться только в коде по работе с оверлеями. Добавятся дополнительные ELF Reloc типы.
Компилятор: Clang/LLVM
Отладчик: GDB
Возможно, проект riscv-overlay - это чуть более продвинутое решение, чем использование традиционных оверлеев. И в отличии от традиционных оверлеев, использование таких оверлеев будет чуть проще для пользователя.
Но на момент данного исследования (май 2022) проект riscv-overlay не закончен.
- riscv-software-src/riscv-overlay
- Software Overlay Task Group
- riscv-software-src/riscv-overlay/comrv
- Binutils changes for RISC-V overlay system
- riscv-software-src/riscv-overlay/docs/overlay-hld.adoc
- riscv-software-src/riscv-overlay/docs/
- fossi-foundation/embedded-sw-overlay/docs/
- riscv-software-src/riscv-overlay/meetings/
- LMA и VMA
- Overlay Code with GCC
- ld doc: 3.6.8.2 Output Section LMA
- ld doc: 3.6.9 Overlay Description
- GDB doc: 14 Debugging Programs That Use Overlays
- sifive/freedom-gdb-metal
- riscv-overlay