2025-01-12

vak: (Аристипп)
У меня сегодня огромная радость. Заработала ключевая фича в проекте, который я с переменным успехом двигал последние два года. В операционке FP/M успешно выполняются ELF-бинарники из файловой системы.

Я когда-то упоминал проект RP/M, за это время он переименовался в FP/M. Расшифровывается как Flash Program for Microcontrollers. Должно получиться похоже на CP/M или MS-DOS, но вместо флопика будет Flash-память.

Вот как это нынче выглядит. Подсоединяемся через USB-порт к виртуальной консоли через minicom и пробуем команду 'hello'.



Программа выполняется из файла /bin/hello.exe в файловой системе flash:. Это вместо диска C:. Вместо флопика A: работает файловая система sd: на SD-карточке. Сама программа выглядит так:
#include <fpm/api.h>

int main()
{
fpm_puts("Hello, World!\r\n");
}
Теперь начну готовить первый релиз. Займёт пару недель, я думаю. Нужно сварганить утилитку, создающую исходный образ файловой системы в Flash-памяти.
vak: (Кризис так себе)
«Солдаты, подвергшиеся артиллерийскому обстрелу, должны бежать в сторону ранее пораженного места, поскольку вероятность того, что в одно и то же место попадут дважды, минимальна.»

Говорят, эту премудрость нашли законспектированной в дневнике пойманного северокорейца.
vak: (Default)
Глянем размер простейшей программы для FP/M. Вот исходный код упомянутой hello.exe.
#include <fpm/api.h>

int main()
{
fpm_puts("Hello, World!\r\n");
}
Построим бинарник.
$ arm-none-eabi-gcc -mcpu=cortex-m0plus -mthumb -fPIC -O -Ifpm-base/include -c hello.c
$ arm-fpm-ld -shared -fPIC -e main hello.o -o hello.exe
$ arm-none-eabi-size hello.exe
text data bss dec hex filename
194 144 0 338 152 hello.exe
Вот результат дизассемблирования посредством arm-none-eabi-objdump.
hello.exe:     file format elf32-littlearm

Disassembly of section .plt:

0000011c <.plt>:
11c: b407 push {r0, r1, r2}
11e: 4803 ldr r0, [pc, #12] @ (12c <.plt+0x10>)
120: 6800 ldr r0, [r0, #0]
122: 4903 ldr r1, [pc, #12] @ (130 <.plt+0x14>)
124: 5840 ldr r0, [r0, r1]
126: 9002 str r0, [sp, #8]
128: bd03 pop {r0, r0, pc}
12a: 46c0 nop
12c: 20000010 .word 0x20000010
130: 00000000 .word 0

Disassembly of section .text:

00000134 <main>:
134: b510 push {r4, lr}
136: 4803 ldr r0, [pc, #12] @ (144 <main+0x10>)
138: 4478 add r0, pc
13a: f7ff ffef bl 11c <.plt>
13e: 2000 movs r0, #0
140: bd10 pop {r4, pc}
142: 46c0 nop
144: 0000000c .word 0xc

Disassembly of section .rodata:

00000148 <.rodata>:
148: 6c6c6548
14c: 57202c6f
150: 646c726f
154: 000a0d21
Размер главной функции main() составляет 16 байт комманд и 4 байта константы. Присоединим сюда также 16 байт текста сообщения в секции .rodata. В сумме 36 байт.

Заметьте: системный вызов fpm_puts() выглядит как простой вызов функции с параметрами.

Для каждого такого системного вызова линкер создаёт в секции .plt код размером 24 байта. Его задача - вытащить из глобальной таблицы смещений (GOT, или Global Offset Table) адрес процедуры, реализующей вызов, и туда перейти. Таблицу GOT формирует системный вызов rpm_execv() на стеке при запуске программы на выполнение. И заносит её адрес в таблицу векторов по адресу 20000010. Это для архитектуры ARMv6-M.

То есть весь hello.exe это 36+24 = 60 байт кода программы. Всё остальное в бинарном файле - накладные расходы на формат ELF.

Код здесь позиционно-независимый. На каком адресе файл окажется в файловой Flash-памяти, там и будет выполняться. Лишь бы лежал одним фрагментом.