Arbeiten mit Make und Linker-Script: Unterschied zwischen den Versionen

Aus C und Assembler mit Raspberry
Die Seite wurde neu angelegt: „In diesem Abschnitt werden wir lernen, wie man ein Betriebssystem auf dem Raspberry Pi 5 entwickelt, indem wir mehrere Source-Dateien erstellen und mit dem Linker verknüpfen. Wir werden auch ein Makefile verwenden, um den Build-Prozess zu automatisieren. Zusätzlich werden wir auf C und C++ eingehen. === Ein Makefile erstellen === Ein Makefile hilft uns, den Build-Prozess zu automatisieren und den Überblick über unsere Dateien zu behalten. Hier ist ein…“
 
Zeile 114: Zeile 114:


'''SECTIONS:''' Definiert die verschiedenen Abschnitte des Programms und deren Speicherorte.
'''SECTIONS:''' Definiert die verschiedenen Abschnitte des Programms und deren Speicherorte.
{|
|-
| style="width: 33%; text-align:left;" | [[Programm auf dem Raspberry Pi 5 ausführen|< Zurück]] || style="width: 33%" | [[Hauptseite|^ Hauptseite]] || style="width: 33%; text-align:right;" | [[Unser erstes Programm (PI5)|weiter >]]
|}

Version vom 23. Juli 2024, 09:04 Uhr

In diesem Abschnitt werden wir lernen, wie man ein Betriebssystem auf dem Raspberry Pi 5 entwickelt, indem wir mehrere Source-Dateien erstellen und mit dem Linker verknüpfen. Wir werden auch ein Makefile verwenden, um den Build-Prozess zu automatisieren. Zusätzlich werden wir auf C und C++ eingehen.

Ein Makefile erstellen

Ein Makefile hilft uns, den Build-Prozess zu automatisieren und den Überblick über unsere Dateien zu behalten. Hier ist ein Beispiel-Makefile:

CSRCS := $(wildcard *.c)
CPPSRCS := $(wildcard *.cpp)
ASRCS := $(wildcard *.S)
COBJS := $(CSRCS:.c=.o)
CPPOBJS := $(CPPSRCS:.cpp=.o)
AOBJS := $(ASRCS:.S=.o)
AllOBJS := $(COBJS) $(CPPOBJS) $(AOBJS)
LOADADDR = 0x80000

GCCFLAGS = -mcpu=cortex-a76 -mlittle-endian -Wall -O0 -ffreestanding \
           -nostartfiles -nostdlib -nostdinc -g -I ./include

AFLAGS = -mcpu=cortex-a76 -mlittle-endian  -I ./include -O0 -g

CFLAGS = -mcpu=cortex-a76 -mlittle-endian -Wall -fsigned-char -ffreestanding -g \
         -I ./include -O0 -fno-exceptions 

CPPFLAGS = -fno-exceptions -fno-rtti -nostdinc++ -mcpu=cortex-a76 -mlittle-endian -Wall -fsigned-char \
			  -ffreestanding -g -I ./include -O0 -mstrict-align -std=c++14 -Wno-aligned-new

all: clean new kernel_2712.img

%.o: %.S
	@echo "as $@"
	@aarch64-none-elf-gcc $(AFLAGS) -c $< -o $@

%.o: %.c
	@echo "gcc $@"
	@aarch64-none-elf-gcc $(CFLAGS) -c $< -o $@

%.o: %.cpp
	@echo "g++ $@"
	@aarch64-none-elf-g++ $(CPPFLAGS) -c $< -o $@

kernel_2712.img: $(AllOBJS)
	@echo "============================================================================="
	@echo "Linking..."
	@aarch64-none-elf-ld -o kernel_2712.elf -Map kernel_2712.map -nostdlib \
		--section-start=.init=$(LOADADDR) --no-warn-rwx-segments \
		-g -T linker.ld $(AllOBJS)
	aarch64-none-elf-objcopy -O binary kernel_2712.elf kernel_2712.img

clean:
	/bin/rm -f kernel_2712.elf *.o *.img > /dev/null 2> /dev/null || true

new:
	/bin/clear

Erklärung des Makefiles

Variablen definieren: Die ersten Zeilen des Makefiles definieren Variablen, die die Quelldateien (C, C++ und Assembler) und deren Objektdateien enthalten.

Compiler-Flags: Die Flags GCCFLAGS, AFLAGS, CFLAGS und CPPFLAGS enthalten die Compiler-Optionen für die verschiedenen Dateitypen.

Build-Ziele:

all: Dieses Ziel löscht alte Dateien (clean), leert den Bildschirm (new) und erstellt den Kernel (kernel_2712.img).

%.o: %.S, %.o: %.c, %.o: %.cpp: Diese Regeln definieren, wie Assembler-, C- und C++-Quellcode in Objektdateien kompiliert werden.

kernel_2712.img: Dieses Ziel verlinkt alle Objektdateien und erzeugt die finale binäre Datei kernel_2712.img.

clean: Löscht alle erstellten Dateien.

new: Leert den Bildschirm.

Das Linker-Script

Ein Linker-Script bestimmt, wie der Linker die verschiedenen Abschnitte des Programms im Speicher anordnet. Hier ist ein Beispiel für ein Linker-Script:

ENTRY(_start)

SECTIONS
{
	.init : {
		*(.init)
	}
	.text : {
		*(.text*)
		_etext = .;
	}
	.rodata : {
		*(.rodata*)
	}
	.init_array : {
		__init_start = .;
		KEEP(*(.init_array*))
		__init_end = .;
	}
	.ARM.exidx : {
		__exidx_start = .;
		*(.ARM.exidx*)
		__exidx_end = .;
	}
	.eh_frame : {
		*(.eh_frame*)
	}
	.data : {
		*(.data*)
	}
	.bss : {
		__bss_start = .;
		*(.bss*)
		*(COMMON)
		__bss_end = .;
	}
}
__bss_size = (__bss_end - __bss_start) >> 3;

bennenne diese Datei als “linker.ld”

Erklärung des Linker-Scripts

ENTRY(_start): Definiert den Startpunkt des Programms.

SECTIONS: Definiert die verschiedenen Abschnitte des Programms und deren Speicherorte.

< Zurück ^ Hauptseite weiter >