Лисья Нора

Оглавление


§ Целевая система

Так как компилятор GCC категорически не может работать с 16-битными регистрами и инструкциями, минимально что он понимает это 32-бит. Поэтому настройка будет именно под эту платформу. Тем более, 386 процессор был минимум 32-битным.

§ Шаблон makefile

CC=gcc
COPT=-m32 -Os -ffreestanding -nostdlib -fno-pie -mno-sse -static
CCPT=-ffunction-sections -fdata-sections -flto
LOPT=-T main.ld -Wl,--build-id=none -Wl,-z,notext -Wl,--gc-sections
DEPS=nasm.o main.o
 
all: load dump
load:
nasm -felf32 -o nasm.o main.asm
$(CC) $(COPT) $(CCPT) -c main.cc -o main.o
$(CC) $(COPT) $(DEPS) $(LOPT) -o main.elf
objcopy -O binary main.elf main.bin
dump:
objdump -S -M intel main.elf > main.lst
Описание флагов компилятора.

§ Файл линковщика

ENTRY(_start)
 
MEMORY
{
ROM (rx) : ORIGIN = 0x008000, LENGTH = 32K
RAM (rwx) : ORIGIN = 0x100000, LENGTH = 1M
}
 
SECTIONS
{
/* Код программы и константы (в ROM) */
.text :
{
KEEP(*(.text._start)) /* Гарантируем, что _start будет первым */
*(.text*) /* Все остальные функции */
*(.rodata*) /* Константы */
} > ROM
 
/* Инициализированные данные */
.data :
{
_sdata = .; /* Начало секции в RAM */
*(.data*)
_edata = .; /* Конец секции в RAM */
} > RAM AT > ROM
 
/* Физический адрес начала данных в ROM */
_sidata = LOADADDR(.data);
 
/* Неинициализированные данные */
.bss :
{
_sbss = .;
*(COMMON)
*(.bss*)
_ebss = .;
} > RAM
 
/DISCARD/ :
{
*(.note.gnu.build-id)
*(.note.ABI-tag)
*(.comment)
}
 
/* Определяем вершину стека (в конце RAM) */
_stack_top = ORIGIN(RAM) + LENGTH(RAM);
}
В файле линкера есть переменные, к примеру _sdata, _edata, _sidata – они указывают на начало данных в ROM (_sidata), а также на начало данных в RAM (с _sdata по _edata). Это глобальные данные, которые должны быть обязательно скопированы в ОЗУ перед использованием самой программой.
Тоже касается и BSS: это секция, которая должна быть пустой в памяти и очищена в нули.

§ Бутфайл

[bits 32]
 
global _start
extern main
extern _stack_top
extern _sidata, _sdata, _edata, _sbss, _ebss
 
section .text
 
_start:
 
mov esp, _stack_top
 
; Копирование данных
mov esi, _sidata
mov edi, _sdata
mov ecx, _edata
sub ecx, _sdata
jz _nodata
rep movsb
_nodata:
 
; Начало BSS
mov ecx, _ebss
sub ecx, _sbss
jz _nobss
xor eax, eax
rep stosb
_nobss: call main
_fin: jmp _fin
 
section .note.GNU-stack noalloc noexec nowrite progbits