Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Bernhard Heinloth
OOStuBS - WS18
Commits
395a8e97
Commit
395a8e97
authored
Oct 25, 2018
by
Bernhard Heinloth
Browse files
Vorgabe oostubs Aufgabe 1
parent
29fc36a8
Changes
46
Expand all
Hide whitespace changes
Inline
Side-by-side
Makefile
0 → 100644
View file @
395a8e97
# vim: set et ts=4 sw=4:
# -----------------------------------------------------------------------------
#
# M A K E F I L E
#
# Zum Uebungsbetriebssystem OO/MP-StuBS der Lehrveranstaltung Betriebssysteme.
# -----------------------------------------------------------------------------
#
# Durch Eingabe von 'make' werden die Quelltexte des Systems kompiliert.
# Es gibt Targets in mehreren Varianten, <name>, <name>-noopt sowie
# <name>-verbose.
# Targets mit dem Suffix -noopt werden ohne Optimierungen kompiliert. Dies
# kann sich z.B. für das Debugging mit gdb eignen.
# Bei dem Suffix -verbose werden umfangreiche Ausgaben (über den Ausgabestrom
# DBG_VERBOSE) angezeigt, was beim printf-Debugging hilfreich sein kann.
#
# Folgende Targets sind verfügbar (jeweils auch mit -noopt):
# all: Das System wird gebaut und liegt anschließend als ELF-Binary vor.
#
# kvm: KVM wird gestartet und führt euer System in einer
# Hardware-Beschleunigten virtuellen Maschine aus. Dieses Target ruft
# aus Sicherhietsgründen ein CIP-Pool spezifisches Script auf.
#
# netboot: Das System wird in das Netzwerkverzeichnis kopiert und kann auf den
# Testrechner gestartet werden
#
# iso: Erstellt ein bootfähiges Abbild für den Start auf Testrechner
# mittels externe Datenträger
#
# qemu: QEMU wird gestartet und führt euer System aus. Da QEMU langsamer
# ist als KVM treten hier u.U. andere Fehler hervor als in KVM oder
# auf der Hardware.
#
# qemu-iso: QEMU start und führt euer System von der ISO (als CD eingelegt) aus
#
# qemu-gdb: QEMU wird mit aktiviertem GDB-Stub gestartet und eine GDB-Instanz
# angehängt, damit lässt sich euer System Schritt für Schritt
# debuggen
#
# qemu-ddd: Wie qemu-gdb nur dient hier DDD als Frontend.
#
# help: Zeigt eine umfangreiche Hilfe an
#
# -----------------------------------------------------------------------------
# Rewrite 02/2014: gabor
# -----------------------------------------------------------------------------
# --------------------------------------------------------------------------
# Default target
.DEFAULT_GOAL
=
all
# --------------------------------------------------------------------------
# Zu uebersetzende Quelldateien (Wichtig: vor common.mk definieren!)
CC_SOURCES
=
$(
shell
find
.
-name
"*.cc"
-and
!
-name
'.*'
-and
!
-path
'./test*'
-and
!
-path
'./fs/tool/*'
)
ASM_SOURCES
=
$(
shell
find
.
-name
"*.asm"
-and
!
-name
'.*'
-and
!
-name
"startup.asm"
)
STARTUP_SOURCE
=
startup.asm
STARTUP_OBJECT
=
$(OBJDIR)
/_startup.o
# Pfad zum Ordner für Dateien für die initiale Ramdisk (für Aufgabe 7)
INITRD_DIR
?=
initrd/
INITRD_TOOL
?=
fs/tool/fstool
INITRD_DEP
=
# 1MB Freier Speicher
INITRD_FREE
?=
1048576
# --------------------------------------------------------------------------
# Globale Variablen und Standard-Rezepte einbinden
include
common.mk
# -----------------------------------------------------------------------------
# Parameter:
KERNEL
=
$(OBJDIR)
/system
ISOFILE
=
$(OBJDIR)
/stubs.iso
ifneq
($(wildcard $(INITRD_DIR)*),)
INITRD
=
$(OBJDIR)
/initrd.img
INITRD_DEP
+=
$(
shell
find
$(INITRD_DIR)
-type
f
)
$(KERNEL)
:
$(INITRD)
endif
all
:
$(KERNEL)
# Rezept zum Linken des Systemimages
$(KERNEL)
:
$(STARTUP_OBJECT) $(OBJPRE) $(MAKEFILE_LIST)
@
echo
"LD
$@
"
@
if
test
\(
!
\(
-d
$
(
@D
)
\)
\)
;
then
mkdir
-p
$
(
@D
)
;
fi
$(VERBOSE)
$(LD)
-e
startup
-T
boot/sections.ld
-o
$(KERNEL)
$(LDFLAGS)
$(STARTUP_OBJECT)
$(LDHEAD)
$(OBJPRE)
$(LDTAIL)
$(LDLIBS)
# Tool zum Bearbeiten eines Minix-v3 Abbildes (Aufgabe 7)
$(INITRD_TOOL)
:
$(shell test -d $(dir $(INITRD_TOOL)) && find $(dir $(INITRD_TOOL)) -name "*.cc" -or -name '*.h')
@
echo
"Make
$@
"
@
make
-C
$(
dir
$(INITRD_TOOL)
)
# Ramdisk mit Minix v3 Dateisystem
$(INITRD)
:
$(INITRD_TOOL) $(INITRD_DEP)
@
echo
"INITRD
$@
"
@
dd
if
=
/dev/zero
of
=
$@
bs
=
$(
shell
du
-s
$(INITRD_DIR)
|
cut
-f1
| xargs
expr
$(INITRD_FREE)
+
)
count
=
1
@
/sbin/mkfs.minix
-3
$@
# optional --inodes <number>
@
./
$(INITRD_TOOL)
put
"
$(INITRD_DIR)
"
$@
boot/sections.ld
0 → 100644
View file @
395a8e97
/* vim: set et ts=4 sw=4: */
SECTIONS
{
. = 0x1000000; /* Startadresse des Systems */
.text :
{
*(".text")
*(".text$")
*(".init")
*(".fini")
*(".gnu.linkonce.*")
}
/* Liste von Startadressen der globalen Konstruktoren (benoetigt ab gcc 4.7) */
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
}
.data :
{
*(".data")
*(".data$")
*(".rodata")
___CTOR_LIST__ = .;
*(".ctors")
*(".ctor")
___CTOR_LIST_END__ = .;
___DTOR_LIST__ = .;
*(".dtors")
*(".dtor")
___DTOR_LIST_END__ = .;
*(".got")
*(".got.plt")
*(".eh_frame")
*(".eh_fram")
*(".jcr")
}
/* Startcode fuer die APs, wird von SMPSystem::copyStartAPtoLowMem() reloziert */
.setup_ap_seg ALIGN(0x10) :
{
___SETUP_AP_START__ = .;
*(".setup_ap_seg")
*(".setup_ap_seg$")
___SETUP_AP_END__ = .;
}
.vesa_detection ALIGN(0x10):
{
__VESA_DETECTION_CODE_START__ = .;
*(".vesa_detection")
*(".vesa_detection$")
__VESA_DETECTION_CODE_END__ = .;
}
.bss :
{
*(".bss")
*(".bss.*")
*(COMMON)
}
___IMG_END___ = .;
/*
/DISCARD/ :
{
*(".note")
*(".comment")
*(".debug_line")
*(".debug_info")
*(".debug_abbrev")
*(".debug_aranges")
}
*/
}
boot/startup.asm
0 → 100644
View file @
395a8e97
; vim: set et ts=4 sw=4:
;******************************************************************************
;* Betriebssysteme *
;*----------------------------------------------------------------------------*
;* *
;* S T A R T U P . A S M *
;* *
;*----------------------------------------------------------------------------*
;* 'startup' ist der Eintrittspunkt des eigentlichen Systems. Die Umschaltung *
;* in den 'Protected Mode' ist bereits erfolgt. Es wird alles vorbereitet, *
;* damit so schnell wie moeglich die weitere Ausfuehrung durch C/C++-Code *
;* erfolgen kann. *
;******************************************************************************
; Multiboot-Konstanten
MULTIBOOT_PAGE_ALIGN
equ
1
<<
0
MULTIBOOT_MEMORY_INFO
equ
1
<<
1
MULTIBOOT_HEADER_MAGIC
equ
0x1badb002
MULTIBOOT_HEADER_FLAGS
equ
MULTIBOOT_PAGE_ALIGN
|
MULTIBOOT_MEMORY_INFO
MULTIBOOT_HEADER_CHKSUM
equ
-
(
MULTIBOOT_HEADER_MAGIC
+
MULTIBOOT_HEADER_FLAGS
)
MULTIBOOT_START_ADDRESS
equ
0x1000000
INIT_STACK_SIZE
equ
(
1024
*
4
)
; Deskriptoren global machen für realmode.asm
[
GLOBAL
idt_desc_global
]
; Globaler Einsprungspunkt für das System
[
GLOBAL
startup
]
; externe Funktionen und Variablen, die hier benötigt werden
[
EXTERN
multiboot_addr
]
; Adresse der Multiboot Strukturen
[
EXTERN
guardian
]
; Wird zur Interruptbehandlung aufgerufen
[
EXTERN
ap_stack
]
; hier liegt die Adresse des Stacks für den gerade gebooteten AP
[
EXTERN
kernel_init
]
; Wird zur Interruptbehandlung aufgerufen
[
EXTERN
gdt_desc_global
]
; Der "Pointer" zur globalen Deskriptortabelle (machine/gdt.cc)
[
SECTION
.text
]
startup:
jmp
skip_multiboot_hdr
; multiboot header, auch der Zugriff über das Symbol ist aligned
align
4
multiboot_header:
dd
MULTIBOOT_HEADER_MAGIC
dd
MULTIBOOT_HEADER_FLAGS
dd
MULTIBOOT_HEADER_CHKSUM
skip_multiboot_hdr:
; Adresse der Multiboot-Strukturen speichern
mov
[
multiboot_addr
],
ebx
; Unterbrechungen sperren
cli
; NMI verbieten
mov
al
,
0x80
out
0x70
,
al
mov
dword
[
ap_stack
],
init_stack
+
INIT_STACK_SIZE
segment_init:
; GDT setzen
lgdt
[
gdt_desc_global
]
; Unterbrechungsbehandlung sicherstellen
lidt
[
idt_desc_global
]
; Datensegmentregister initialisieren
mov
ax
,
0x10
mov
ds
,
ax
mov
es
,
ax
mov
fs
,
ax
mov
gs
,
ax
mov
ss
,
ax
; cs Segment Register neu laden
jmp
0x8
:
load_cs
load_cs:
; Stackpointer initialisieren
mov
esp
,
[
ap_stack
]
; Richtung für String-Operationen festlegen
cld
; Wechsel in C/C++
call
kernel_init
; Startup-Code fuer die APs
startup_ap:
; Alle Segmentselektoren neu laden, die zeigen noch auf die ap_gdt
; Nach Intel Manual Kapitel 9.9.1 ist das nötig
mov
ax
,
0x10
mov
ds
,
ax
mov
es
,
ax
mov
fs
,
ax
mov
gs
,
ax
mov
ss
,
ax
; jetzt ist die CPU im protected mode
jmp
seg
ment_init
;Unterbrechungsbehandlungen
; Die Interruptbehandlung muss in Assembler gestartet werden, um die
;; IRQ <irq-num> <error-code?>
%macro IRQ 2
align
8
irq_entry_
%
1
:
;; Den CPU Kontext Sichern
push
edx
push
ecx
push
eax
;; Einen Pointer auf den CPU Kontext als zweites Argument pushen
push
esp
;; Die Interrupt-Nummer ist das erste Argument
push
%
1
call
guardian
add
esp
,
8
; CPU Kontext und IRQ-Nummer vom Stack nehmen
pop
eax
pop
ecx
pop
edx
iret
%endmacro
IRQ
0
,
0
IRQ
1
,
0
IRQ
2
,
0
IRQ
3
,
0
IRQ
4
,
0
IRQ
5
,
0
IRQ
6
,
0
IRQ
7
,
0
IRQ
8
,
1
IRQ
9
,
0
IRQ
10
,
1
IRQ
11
,
1
IRQ
12
,
1
IRQ
13
,
1
IRQ
14
,
1
IRQ
15
,
0
IRQ
16
,
0
IRQ
17
,
1
%assign i 18
%rep 238
IRQ
i
,
0
%assign i i+1
%endrep
[
SECTION
.data
]
; 'interrupt descriptor table' mit 256 Eintraegen.
align
4
idt:
%macro idt_entry 1
dw
(
irq_entry_
%
1
-
startup
+
MULTIBOOT_START_ADDRESS
)
&
0xffff
dw
0x0008
dw
0x8e00
dw
((
irq_entry_
%
1
-
startup
+
MULTIBOOT_START_ADDRESS
)
&
0xffff0000
)
>>
16
%endmacro
%assign i 0
%rep 256
idt_entry
i
%assign i i+1
%endrep
idt_desc_global:
dw
256
*
8
-
1
; idt enthaelt 256 Eintraege
dd
idt
[
SECTION
.bss
]
init_stack:
resb
INIT_STACK_SIZE
; setup_ap, Start der restlichen Prozessoren
; Umschaltung in den 'Protected-Mode'
; Dieser Code wird von APICSystem::copySetupAPtoLowMem() reloziert!
[
SECTION
.setup_ap_seg
]
USE16
setup_ap:
; Segmentregister initialisieren
mov
ax
,
cs
; Daten- und Codesegment sollen
mov
ds
,
ax
; hierher zeigen. Stack brauchen wir hier nicht.
; Unterbrechungen sperren
cli
; NMI verbieten
mov
al
,
0x80
out
0x70
,
al
; vorrübergehende GDT setzen
lgdt
[
ap_gdtd
-
setup_ap
]
; Umschalten in den Protected Mode
mov
eax
,
cr0
; Setze PM bit im Kontrollregister 1
or
eax
,
1
mov
cr0
,
eax
jmp
dword
0x08
:
startup_ap
align
4
ap_gdt:
dw
0
,
0
,
0
,
0
; NULL Deskriptor
; Codesegment von 0-4GB
dw
0xFFFF
; 4Gb - (0x100000*0x1000 = 4Gb)
dw
0x0000
; base address=0
dw
0x9A00
; code read/exec
dw
0x00CF
; granularity=4096, 386 (+5th nibble of limit)
; Datensegment von 0-4GB
dw
0xFFFF
; 4Gb - (0x100000*0x1000 = 4Gb)
dw
0x0000
; base address=0
dw
0x9200
; data read/write
dw
0x00CF
; granularity=4096, 386 (+5th nibble of limit)
ap_gdtd:
dw
$
-
ap_gdt
-
1
; Limit
dd
0x40000
+
ap_gdt
-
setup_ap
; Physikalische Adresse der ap_gdt
boot/startup.cc
0 → 100644
View file @
395a8e97
// vim: set et ts=4 sw=4:
/*! \file
* \brief Enthält Funktionen für den Systemstart, die nicht mehr in
* Assembler geschrieben werden müssen.
*/
#include
"types.h"
#include
"machine/apicsystem.h"
#include
"machine/cpu.h"
#include
"machine/io_port.h"
/*! \brief Die Zeiger auf die Multiboot-Strukturen wird vom Assembler-
* startup zugewiesen.
*/
void
*
multiboot_addr
=
0
;
/*! \brief Hilfsfunktion der PIT-Initialisierung, die ein kurzes Delay
* verursacht.
*/
static
void
delay
()
{
asm
volatile
(
"nop
\n\t
"
:::
"memory"
);
}
/*! \brief Initalisierung der PICs (Programmierbare Interrupt-Controller),
* damit alle 15 Hardware-Interrupts nacheinander in der idt liegen.
*/
static
void
initialise_pics
()
{
IO_Port
p20
(
0x20
);
IO_Port
p21
(
0x21
);
IO_Port
pa0
(
0xa0
);
IO_Port
pa1
(
0xa1
);
//ICW1: 8086 Modus mit ICW4
p20
.
outb
(
0x11
);
delay
();
pa0
.
outb
(
0x11
);
delay
();
//ICW2 Master: IRQ # Offset (32)
p21
.
outb
(
0x20
);
delay
();
//ICW2 Slave: IRQ # Offset (40)
pa1
.
outb
(
0x28
);
delay
();
//ICW3 Master: Slaves an IRQs
p21
.
outb
(
0x04
);
delay
();
//ICW3 Slave: Verbunden mit IRQ2 des Masters
pa1
.
outb
(
0x02
);
delay
();
//ICW4: 8086 Modus und automatischer EIO
p21
.
outb
(
0x03
);
delay
();
pa1
.
outb
(
0x03
);
delay
();
//Alle Hardware-Interrupts durch Legacy-PICs ausmaskieren.
pa1
.
outb
(
0xff
);
delay
();
p21
.
outb
(
0xff
);
}
/*! \brief Ab gcc 4.7 weitere Initialisierung globaler Objekte.
*
*/
static
void
csu_init
()
{
extern
void
(
*
__init_array_start
[])
();
extern
void
(
*
__init_array_end
[])
();
const
size_t
size
=
__init_array_end
-
__init_array_start
;
for
(
size_t
i
=
0
;
i
<
size
;
i
++
)
{
(
*
__init_array_start
[
i
])();
}
}
extern
"C"
void
_init
();
extern
"C"
void
_fini
();
extern
"C"
int
main_ap
()
__attribute__
((
weak
));
extern
"C"
int
main
();
static
bool
bootCPU
=
true
;
extern
"C"
void
kernel_init
()
{
if
(
bootCPU
)
{
bootCPU
=
false
;
//initialisierung der PICs
initialise_pics
();
//Aufruf globaler Konstruktoren
_init
();
csu_init
();
//weitere Initialisierungen
system
.
detectSystemType
();
system
.
setupThisProcessor
();
//Die main-Funktion
main
();
//falls die main-Funktion zurückkehren sollte werden die Destruktoren
//globaler Objekte aufgerufen
_fini
();
}
else
{
// Initialisiere diesen AP Prozessor
system
.
setupThisProcessor
();
// Springe die Anwendung an.
main_ap
();
}
for
(;;)
{
CPU
::
die
();
}
}
common.mk
0 → 100644
View file @
395a8e97
# --------------------------------------------------------------------------
# Einstellungen in Abhaengigkeit vom Generierungssystem:
#
# ASMOBJFORMAT: Ausgabeformat fuer den Assembler. Das Format muss dem
# jeweiligen Format des verwendeten C++ Compilers angepasst
# werde, damit gemischte Objektdateien gelinkt werden koennen.
# OBJDIR: Verzeichnispräfix, in dem die Objektdateien abgelegt werden
# sollen.
# DEPDIR: Verzeichnispräfix, in dem die Abhaengigkeitsdateien abgelegt
# werden sollen
# ISOIR: Verzeichnispräfix, in dem die Daten für das bootfähige
# Medium angelegt werden sollen
# NOOPTTAG: Endung, welche an die Verzeichnisse für Objekt- und
# Abhängigkeitsdateien bei Debugversionen angehängt wird
# VERBOSETAG: Endung ähnlich NOOPTTAG, nur für Builds mit Verboseausgaben
# ASM: Zu benutzender Assembler
# CC/CXX: Zu benutzender C/C++-Compiler
# AR: Zu benutzender Archivierer
# CFLAGS: Flags fuer den C-Compileraufruf
# CXXFLAGS: Flags fuer den C++-Compileraufruf
# LD: Zu benutzender Linker
# LDFLAGS: Flags fuer den Linkeraufruf
# LDLIBS: Dazuzulinkende Bibliotheken
# LDHEAD: Am Anfang zu linkende Dateien
# LDTAIL: Am Ende zu linkende Dateien
VERBOSE
=
@
ASMOBJFORMAT
=
elf
OBJDIR
=
./build
DEPDIR
=
./dep
NOOPTTAG
=
-noopt
VERBOSETAG
=
-verbose
SOLUTIONDIR
=
/proj/i4bs/solution
SOLUTIONPREFIX
=
musterloesung-u
ASM
=
nasm
CXX
=
g++
LD
=
ld
MKISO
=
grub-mkrescue
QEMU
=
qemu-system-i386
PROJECT
=
"OOStuBS"
WARNFLAGS
=
-Wall
-Wextra
-Werror
-Wno-error
=
unused-parameter
OPTFLAGS
=
-O3
-fomit-frame-pointer
FLOATINGPOINT
=
-mno-mmx
-mno-sse
STANDALONEFLAGS
=
-ffreestanding
-fno-builtin
-nodefaultlibs
-nostdlib
-nostdinc
ifeq
($(CXX),g++)
STANDALONEFLAGS
+=
-fno-tree-loop-distribute-patterns
-nostartfiles
WARNFLAGS
+=
-Wstack-usage
=
1024
-Wno-error
=
stack-usage
=
else
ifeq
($(CXX),clang++)
WARNFLAGS
+=
-Wno-error
=
unused-private-field
-Wno-implicit-exception-spec-mismatch
-Wno-error
=
unused-const-variable
endif
CXXFLAGS
=
-std
=
c++11
-m32
-I
.
$(OPTFLAGS)
$(WARNFLAGS)
$(STANDALONEFLAGS)
$(FLOATINGPOINT)
-Wno-non-virtual-dtor
-fno-rtti
-fno-exceptions
-Wno-write-strings
-fno-stack-protector
-mno-red-zone
-g
-gdwarf-2
ASMFLAGS
=
-f
$(ASMOBJFORMAT)
LDFLAGS
=
-melf_i386
LDHEAD
=
$(
shell
$(CXX)
-m32
--print-file-name
=
crti.o
&&
$(CXX)
-m32
--print-file-name
=
crtbegin.o
)
LDTAIL
=
$(
shell
$(CXX)
-m32
--print-file-name
=
crtend.o
&&
$(CXX)
-m32
--print-file-name
=
crtn.o
)
AR
=
ar
QEMUCPUS
=
4
QEMUFLAGS
=
-k
en-us
-serial
pty
-d
guest_errors
INITRD
=
/dev/null
ISODIR
=
./build-iso
ISOBOOTDIR
=
/boot
ISOGRUBCFG
=
$(ISOBOOTDIR)
/grub/grub.cfg
ISOKERNEL
=
$(ISOBOOTDIR)
/kernel
GRUBTIMEOUT
=
2
GRUBBIN
=
/usr/lib/grub/i386-pc
DD
=
dd
XORRISO
=
xorriso
ifeq
(,$(wildcard $(GRUBBIN)))
GRUBBIN
=
/proj/i4bs/tools/grub-i386-pc
endif
# Namen der Unterverzeichnisse mit den Quelltexten
VPATH
=
$(
sort
$(
dir
$(STARTUP_SOURCE)
$(CC_SOURCES)
$(ASM_SOURCES)
))
# -------------------------------------------------------------------------
# Listen mit den Objektdateien, die beim Kompilieren entstehen:
# (Die Eingabevariablen werden vom eigentlichen Makefile zwar erst spaeter
# definiert, sind aber zum Auswertezeitpunkt *dieser* Variablen schon
# verfuegbar.)
STARTUP_OBJECT
=
$(
addprefix
$(OBJDIR)
/,
$(
patsubst
%.asm,_%.o,
$(
notdir
$(STARTUP_SOURCE)
)))
CC_OBJECTS
=
$(
notdir
$(CC_SOURCES:.cc=.o)
)
DEP_FILES
=
$(
patsubst
%.o,
$(DEPDIR)
/%.d,
$(CC_OBJECTS)
)
ASM_OBJECTS
=
$(
patsubst
%.asm,_%.o,
$(
notdir
$(ASM_SOURCES)
))
OBJPRE
=
$(
addprefix
$(OBJDIR)
/,
$(ASM_OBJECTS)
$(CC_OBJECTS)
)
# --------------------------------------------------------------------------
# Standardrezept zur Erzeugung der Abhaengigkeitsdateien
$(DEPDIR)/%.d
:
%.cc $(MAKEFILE_LIST)
@
echo
"DEP
$@
"
@
if
test
\(
!
\(
-d
$
(
@D
)
\)
\)
;
then
mkdir
-p
$
(
@D
)
;
fi
$(VERBOSE)
$(CXX)
$(CXXFLAGS)
-MM
-MT
$(OBJDIR)
/
$*
.o
-MF
$@
$<
# --------------------------------------------------------------------------
# Standardrezept zur Erzeugung von Objektdateien
$(OBJDIR)/%.o
:
%.cc $(MAKEFILE_LIST)
@
echo
"CXX
$@
"
@
if
test
\(
!
\(
-d
$
(
@D
)
\)
\)
;
then
mkdir
-p
$
(
@D
)
;
fi
$(VERBOSE)
$(CXX)
-c
$(CXXFLAGS)
-o
$@
$<
$(OBJDIR)/_%.o
:
%.asm $(MAKEFILE_LIST)
@
echo
"ASM
$@
"
@
if
test
\(
!
\(
-d
$
(
@D
)
\)
\)
;
then
mkdir
-p
$
(
@D
)
;
fi
$(VERBOSE)
$(ASM)
$(ASMFLAGS)
-o
$@
$<
# --------------------------------------------------------------------------
# Standardrezept 'clean' loescht das generierte System, die Objektdateien und
# die Abhaengigkeitsdateien
clean
: