Meaty Skeleton: Difference between revisions
[unchecked revision] | [unchecked revision] |
Content deleted Content added
Undo corrects I disagree with |
No edit summary |
||
(39 intermediate revisions by 20 users not shown) | |||
Line 1:
{{FirstPerson}}
{{You}}
{{BeginnersWarning}}
{{Rating|1}}
{{Kernel designs}}
operating system in the [[Stan Dard]] style suitable for further modification or
as inspiration for your initial operating system version. The [[Bare Bones]]
tutorial only gives you the absolutely minimal code to demonstrate how to
correctly cross-compile a kernel, however this is unsuitable as an example
operating system. Additionally, this tutorial implements neccesary ABI features
needed to satisfy the ABI and compiler contracts to prevent possible mysterious
errors.
This tutorial also serves as the initial template tutorial on how to
Line 28 ⟶ 33:
indirectly other minor Unix and ABI semantics. Adapt what you wish from this
tutorial. Note that the shell script and Make-based build system constructed in
this tutorial is meant for Unix systems
is no pressing need to make this portable across all operating systems as this
is just an example.
Line 48 ⟶ 53:
== Building a Cross-Compiler ==
You ''must'' use a [[GCC Cross-Compiler]] in this tutorial as in the
Line 56 ⟶ 61:
You ''must'' configure your cross-binutils with the <tt>--with-sysroot</tt> option, otherwise linking will mysteriously fail with the ''this linker was not configured to use sysroots'' error message. If you forgot to configure your cross-binutils with that option, you'll have to rebuild it, but you can keep your cross-gcc.
== Dependencies ==
You will need these dependencies in order to complete this tutorial:
* i686-elf toolchain, as discussed above.
* GRUB, for the grub-mkrescue command, along with the appropriate runtime files.
* Xorriso, the .iso creation engine used by grub-mkrescue.
* GNU make 4.0 or later.
* Qemu, optionally for testing the operating system.
This tutorial requires a GNU/Linux system, or a similar enough system. The BSD systems may almost work. OS X is not supported but can possibly be made to work with some changes. Windows is not supported, but Windows environments like Cygwin and Windows Subsystem For Linux (WSL) might work.
=== Debian-family Users ===
Install the i686-elf toolchain as described above and then install the packages <tt>xorriso grub-pc-bin</tt>.
== System Root ==
Line 71 ⟶ 92:
The <tt>/home/bwayne/myos/sysroot</tt> directory acts as a fake root directory for your operating system. This is called a system root, or ''sysroot''.
You can think of the sysroot as the root directory for your operating system. Your build process will build each component of your operating system (kernel, standard library, programs) and gradually install them into the system root. Ultimately the system root will be a fully functional root filesystem for your operating system, you format a partition and copy the files there, add the appropriate configuration files, configure a bootloader to load the kernel from there, and use your harddisk driver and filesystem driver to read the files from there. The system root is thus a temporary directory that will ultimately become the actual root directory of your operating system.
In this example the cross system root is located as <tt>sysroot/</tt>, which is
Line 80 ⟶ 101:
<tt>sysroot/boot</tt> directory.
We already use system roots
The <tt>-elf</tt> targets have no user-space and are incapable of having one. We configured the compiler with system root support, so it will look in <tt>${SYSROOT}/usr/lib</tt> as expected. We prevented the compiler from searching for a standard library using the --without-headers option when building <tt>i686-elf-gcc</tt>, so it will ''not'' look in <tt>${SYSROOT}/usr/include</tt>. (Once you add a user-space and a libc, you will configure your custom cross-gcc with <tt>--with-sysroot</tt> and it will look in <tt>${SYSROOT}/usr/include</tt>. As a temporary work-around until you get that far, we fix it by passing <tt>-isystem=/usr/include</tt>).
You can change the system root directory layout if you wish, but you will have to modify some
== System Headers ==
Line 92 ⟶ 113:
cross-compile your operating system. This is <tt>useful</tt> as it allows you to
provide the compiler a copy of your headers before you actually compile your
system. You will [[Hosted_GCC_Cross-Compiler#Sysroot_Headers|need to provide the
standard library headers]] when you build a [[Hosted GCC Cross-Compiler]] in the
future that is capable of an user-space.
Note how your cross-compiler comes with a number of fully freestanding headers
Line 108 ⟶ 130:
are used, while a default is used if the user has no opinion. The makefiles also
make sure that particular options are always in CFLAGS. This is done by having
two phases in the makefiles: one that
mandatory options the project makefile requires:
<
# Default CFLAGS:
CFLAGS?=-O2 -g
Line 117 ⟶ 139:
# Add mandatory options to CFLAGS:
CFLAGS:=$(CFLAGS) -Wall -Wextra
</syntaxhighlight>
== Architecture Directories ==
Line 139 ⟶ 161:
from the main kernel.
GNU GRUB is used as the bootloader and the kernel uses
[[Bare Bones]] tutorial.
The kernel implements the correct way of [[Calling_Global_Constructors|invoking
global constructors]] (useful for C++ code and C code using
<tt>__attribute__((constructor))</tt>. The
which invokes all the global constructors. These are invoked very early in the
boot without any specific ordering. You should only use them to initialize
global variables that could not be initialized at runtime.
The special <tt>
it is part of the kernel.
== libc and libk Design ==
Line 188 ⟶ 199:
The standard headers use a BSD-like scheme where <tt>sys/cdefs.h</tt> declares
a bunch of useful preprocessor macros meant for internal use by the standard
library.
<tt>extern "C" {</tt> and <tt>}</tt> such that C++ code can correctly
link against libc (as libc doesn't use C++ linkage). Note also how the compiler
provides the internal keyword __restrict unconditionally (even in C89) mode,
which is useful for adding the restrict keyword to function prototypes even when
compiling code in pre-C99 or C++ mode.
The special <tt>
it is part of the libc
whether it's part of the libk binary.
This example comes with a small number of standard functions that serve as
examples and serve to satisfy ABI requirements. Note that the <tt>printf</tt>
function included is very minimal and intentionally doesn't handle most common
features.
== Source Code ==
Line 211 ⟶ 223:
--->
You can easily download the source code using [[
<
git clone https://
</syntaxhighlight>
Check for differences between the git revision used in this article and what you cloned (empty output means there is no difference):
<syntaxhighlight lang="bash">
git diff 084d1624bedaa9f9e395f055c6bd99299bd97f58..master
</syntaxhighlight>
Operating systems development is about being an expert. Take the time to read the code carefully through and understand it. Please seek further information and help if you don't understand aspects of it. This code is minimal and almost everything is done deliberately, often to pre-emptively solve future problems.
=== kernel ===
==== kernel/include/kernel/tty.h ====
<
#ifndef _KERNEL_TTY_H
#define _KERNEL_TTY_H
Line 289 ⟶ 252:
#endif
</syntaxhighlight>
==== kernel/Makefile ====
<
HOST?=DEFAULT_HOST
HOSTARCH!=../target-triplet-to-arch.sh $(HOST)
CFLAGS?=-O2 -g
Line 308 ⟶ 272:
INCLUDEDIR?=$(PREFIX)/include
CFLAGS:=$(CFLAGS) -ffreestanding
CPPFLAGS:=$(CPPFLAGS) -
LDFLAGS:=$(LDFLAGS)
LIBS:=$(LIBS) -nostdlib -lk -lgcc
ARCHDIR
include $(ARCHDIR)/make.config
CFLAGS:=$(CFLAGS) $(KERNEL_ARCH_CFLAGS)
LDFLAGS:=$(LDFLAGS) $(KERNEL_ARCH_LDFLAGS)
LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS)
KERNEL_OBJS=\
$(KERNEL_ARCH_OBJS) \
kernel/kernel.o \
OBJS=\
$(ARCHDIR)/crti.o \
$(ARCHDIR)/crtbegin.o \
$(KERNEL_OBJS) \
$(ARCHDIR)/crtend.o \
$(ARCHDIR)/crtn.o \
LINK_LIST=\
$(
$(
$(
$(KERNEL_OBJS) \
$(LIBS) \
$(ARCHDIR)/crtend.o \
$(ARCHDIR)/crtn.o \
.PHONY: all clean install install-headers install-kernel
.SUFFIXES: .o .c .S
all: myos.kernel
myos.kernel: $(OBJS) $(ARCHDIR)/linker.ld
$(CC) -T $(ARCHDIR)/linker.ld -o $@ $(CFLAGS) $(LINK_LIST)
grub-file --is-x86-multiboot myos.kernel
OBJ=`$(CC) $(CFLAGS) $(LDFLAGS) -print-file-name=$(@F)` && cp "$$OBJ" $@
$(CC) -MD -c $< -o $@ -std=gnu11 $(CFLAGS) $(CPPFLAGS)
$(CC) -MD -c $< -o $@ $(CFLAGS) $(CPPFLAGS)
clean:
rm -f myos.kernel
rm -f $(OBJS) *.o */*.o */*/*.o
rm -f $(OBJS:.o=.d) *.d */*.d */*/*.d
install: install-headers install-kernel
Line 363 ⟶ 333:
install-headers:
mkdir -p $(DESTDIR)$(INCLUDEDIR)
cp -
install-kernel: myos.kernel
mkdir -p $(DESTDIR)$(BOOTDIR)
cp myos.kernel $(DESTDIR)$(BOOTDIR)
-include $(OBJS:.o=.d)
</syntaxhighlight>
==== kernel/kernel/kernel.c ====
<
#include <stdio.h>
#include <kernel/tty.h>
void
terminal_initialize();
printf("Hello, kernel World!\n");
}
</syntaxhighlight>
==== kernel/arch/i386/tty.c ====
<
#include <stdbool.h>
#include <stddef.h>
Line 399 ⟶ 363:
#include <string.h>
#include <kernel/
#include "vga.h"
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;
static uint16_t* const VGA_MEMORY = (uint16_t*) 0xB8000;
static size_t terminal_row;
static size_t terminal_column;
static uint8_t terminal_color;
static uint16_t* terminal_buffer;
void terminal_initialize(void) {
terminal_row = 0;
terminal_column = 0;
terminal_color =
terminal_buffer = VGA_MEMORY;
for (
for (size_t x = 0; x < VGA_WIDTH; x++) {
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] =
}
}
}
void terminal_setcolor(uint8_t color) {
terminal_color = color;
}
void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y) {
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] =
}
void
int loop;
char c;
for(loop = line * (VGA_WIDTH * 2) + 0xB8000; loop < VGA_WIDTH * 2; loop++) {
c = *loop;
*(loop - (VGA_WIDTH * 2)) = c;
}
}
void terminal_delete_last_line() {
int x, *ptr;
for(x = 0; x < VGA_WIDTH * 2; x++) {
ptr = 0xB8000 + (VGA_WIDTH * 2) * (VGA_HEIGHT - 1) + x;
*ptr = 0;
}
}
void terminal_putchar(char c) {
int line;
unsigned char uc = c;
terminal_putentryat(uc, terminal_color, terminal_column, terminal_row);
if (++terminal_column == VGA_WIDTH) {
terminal_column = 0;
if (
{
for(line = 1; line <= VGA_HEIGHT - 1; line++)
{
terminal_scroll(line);
}
terminal_delete_last_line();
terminal_row = VGA_HEIGHT - 1;
}
}
}
void terminal_write(const char* data, size_t size) {
for (size_t i = 0; i < size; i++)
terminal_putchar(data[i]);
}
void terminal_writestring(const char* data) {
terminal_write(data, strlen(data));
}
</syntaxhighlight>
==== kernel/arch/i386/crtn.S ====
Line 471 ⟶ 459:
ret
</pre>
==== kernel/arch/i386/vga.h ====
<syntaxhighlight lang="c">
#ifndef ARCH_I386_VGA_H
#define ARCH_I386_VGA_H
#include <stdint.h>
enum vga_color {
VGA_COLOR_BLACK = 0,
VGA_COLOR_BLUE = 1,
VGA_COLOR_GREEN = 2,
VGA_COLOR_CYAN = 3,
VGA_COLOR_RED = 4,
VGA_COLOR_MAGENTA = 5,
VGA_COLOR_BROWN = 6,
VGA_COLOR_LIGHT_GREY = 7,
VGA_COLOR_DARK_GREY = 8,
VGA_COLOR_LIGHT_BLUE = 9,
VGA_COLOR_LIGHT_GREEN = 10,
VGA_COLOR_LIGHT_CYAN = 11,
VGA_COLOR_LIGHT_RED = 12,
VGA_COLOR_LIGHT_MAGENTA = 13,
VGA_COLOR_LIGHT_BROWN = 14,
VGA_COLOR_WHITE = 15,
};
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) {
return fg | bg << 4;
}
static inline uint16_t vga_entry(unsigned char uc, uint8_t color) {
return (uint16_t) uc | (uint16_t) color << 8;
}
#endif
</syntaxhighlight>
==== kernel/arch/i386/make.config ====
<
KERNEL_ARCH_CFLAGS
KERNEL_ARCH_CPPFLAGS
KERNEL_ARCH_LDFLAGS
KERNEL_ARCH_LIBS
KERNEL_ARCH_OBJS
$(ARCHDIR)/boot.o \
$(ARCHDIR)/tty.o \
</syntaxhighlight>
==== kernel/arch/i386/crti.S ====
Line 546 ⟶ 572:
*(COMMON)
*(.bss)
}
Line 557 ⟶ 582:
<pre>
# Declare constants
.set ALIGN, 1<<0 # align loaded modules on page boundaries
.set MEMINFO, 1<<1 # provide memory map
Line 572 ⟶ 597:
# Reserve a stack for the initial thread.
.section .
.align 16
stack_bottom:
.skip 16384 # 16 KiB
Line 583 ⟶ 609:
_start:
movl $stack_top, %esp
# Call the global constructors.
Line 595 ⟶ 618:
# Hang if kernel_main unexpectedly returns.
cli
jmp 1b
.size _start, . - _start
</pre>
Line 604 ⟶ 626:
<pre>
*.
*.kernel
*.o
</pre>
Line 612 ⟶ 635:
==== libc/include/string.h ====
<
#ifndef _STRING_H
#define _STRING_H 1
Line 635 ⟶ 658:
#endif
</syntaxhighlight>
==== libc/include/stdio.h ====
<
#ifndef _STDIO_H
#define _STDIO_H 1
#include <sys/cdefs.h>
#define EOF (-1)
#ifdef __cplusplus
Line 658 ⟶ 683:
#endif
</syntaxhighlight>
==== libc/include/sys/cdefs.h ====
<
#ifndef _SYS_CDEFS_H
#define _SYS_CDEFS_H 1
Line 669 ⟶ 694:
#endif
</syntaxhighlight>
==== libc/include/stdlib.h ====
<
#ifndef _STDLIB_H
#define _STDLIB_H 1
Line 691 ⟶ 716:
#endif
</syntaxhighlight>
==== libc/Makefile ====
<
HOST?=DEFAULT_HOST
HOSTARCH!=../target-triplet-to-arch.sh $(HOST)
CFLAGS?=-O2 -g
Line 710 ⟶ 736:
LIBDIR?=$(EXEC_PREFIX)/lib
CFLAGS:=$(CFLAGS) -ffreestanding -Wall -Wextra
CPPFLAGS:=$(CPPFLAGS) -
LIBK_CFLAGS:=$(CFLAGS)
LIBK_CPPFLAGS:=$(CPPFLAGS) -
ARCHDIR
include $(ARCHDIR)/make.config
CFLAGS:=$(CFLAGS) $(ARCH_CFLAGS)
LIBK_CFLAGS:=$(LIBK_CFLAGS) $(KERNEL_ARCH_CFLAGS)
FREEOBJS
$(ARCH_FREEOBJS) \
stdio/printf.o \
Line 736 ⟶ 762:
string/strlen.o \
HOSTEDOBJS
$(ARCH_HOSTEDOBJS) \
OBJS
$(FREEOBJS) \
$(HOSTEDOBJS) \
LIBK_OBJS
#BINARIES=libc.a
BINARIES=libk.a
.PHONY: all clean install install-headers install-libs
.SUFFIXES: .o .libk.o .c .S
all: $(BINARIES)
libc.a: $(OBJS)
$(AR) rcs $@ $(OBJS)
libk.a: $(LIBK_OBJS)
$(AR) rcs $@ $(LIBK_OBJS)
$(CC) -MD -c $< -o $@ -std=gnu11 $(CFLAGS) $(CPPFLAGS)
$(CC) -MD -c $< -o $@ $(CFLAGS) $(CPPFLAGS)
$(CC) -MD -c $< -o $@ -std=gnu11 $(LIBK_CFLAGS) $(LIBK_CPPFLAGS)
$(CC) -MD -c $< -o $@ $(LIBK_CFLAGS) $(LIBK_CPPFLAGS)
clean:
rm -f $(BINARIES
rm -f $(OBJS) $(LIBK_OBJS) *.o */*.o */*/*.o
rm -f $(OBJS:.o=.d) $(LIBK_OBJS:.o=.d) *.d */*.d */*/*.d
install: install-headers install-libs
Line 779 ⟶ 806:
install-headers:
mkdir -p $(DESTDIR)$(INCLUDEDIR)
cp -
install-libs: $(BINARIES)
mkdir -p $(DESTDIR)$(LIBDIR)
cp $(BINARIES) $(DESTDIR)$(LIBDIR)
-include $(OBJS:.o=.d)
-include $(LIBK_OBJS:.o=.d)
</syntaxhighlight>
==== libc/stdlib/abort.c ====
<
#include <stdio.h>
#include <stdlib.h>
__attribute__((__noreturn__))
void abort(void) {
#if defined(__is_libk)
// TODO: Add proper kernel panic.
printf("
asm volatile("hlt");
#else
// TODO: Abnormally terminate the process as if by SIGABRT.
printf("abort()\n");
#endif
while (1) { }
__builtin_unreachable();
}
</syntaxhighlight>
==== libc/string/memmove.c ====
<
#include <string.h>
void* memmove(void* dstptr, const void* srcptr, size_t size) {
unsigned char* dst = (unsigned char*) dstptr;
const unsigned char* src = (const unsigned char*) srcptr;
if (
for (
dst[i] = src[i];
} else {
for (
dst[i-1] = src[i-1];
}
return dstptr;
}
</syntaxhighlight>
==== libc/string/strlen.c ====
<
#include <string.h>
size_t strlen(const char*
size_t len = 0;
while (str[len])
len++;
return len;
}
</syntaxhighlight>
==== libc/string/memcmp.c ====
<
#include <string.h>
int memcmp(const void* aptr, const void* bptr, size_t size) {
const unsigned char* a = (const unsigned char*) aptr;
const unsigned char* b = (const unsigned char*) bptr;
for (
if (
return -1;
else if (
return 1;
}
return 0;
}
</syntaxhighlight>
==== libc/string/memset.c ====
<
#include <string.h>
void* memset(void* bufptr, int value, size_t size) {
unsigned char* buf = (unsigned char*) bufptr;
for (
buf[i] = (unsigned char) value;
return bufptr;
}
</syntaxhighlight>
==== libc/string/memcpy.c ====
<
#include <string.h>
void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size) {
unsigned char* dst = (unsigned char*) dstptr;
const unsigned char* src = (const unsigned char*) srcptr;
for (
dst[i] = src[i];
return dstptr;
}
</syntaxhighlight>
==== libc/stdio/puts.c ====
<
#include <stdio.h>
int puts(const char* string) {
return printf("%s\n", string);
}
</syntaxhighlight>
==== libc/stdio/putchar.c ====
<
#include <stdio.h>
#if defined(
#include <kernel/tty.h>
#endif
int putchar(int ic) {
#if defined(__is_libk)
char c = (char) ic;
terminal_write(&c, sizeof(c));
#else
// TODO:
#endif
return ic;
}
</syntaxhighlight>
==== libc/stdio/printf.c ====
<
#include <limits.h>
#include <stdbool.h>
#include <stdarg.h>
Line 923 ⟶ 953:
#include <string.h>
static
const unsigned char* bytes = (const unsigned char*) data;
for (
if (putchar(bytes[i]) == EOF)
return false;
return true;
}
int printf(const char* restrict format, ...) {
va_list parameters;
va_start(parameters, format);
int written = 0;
while (
size_t maxrem = INT_MAX - written;
if (format[0] != '%' || format[1] == '%') {
if (format[0] == '%')
while (format[amount] && format[amount] != '%')
amount++;
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(format, amount))
return -1;
format += amount;
written += amount;
Line 952 ⟶ 987:
}
const char* format_begun_at = format++;
if (
format++;
char c = (char) va_arg(parameters, int /* char promotes to int */);
if (!maxrem) {
// TODO: Set errno to EOVERFLOW.
return -1;
if (!print(&c, sizeof(c)))
return -1;
written++;
} else if (*format == 's') {
format++;
const char*
if (maxrem < len) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(str, len))
return -1;
written += len;
} else {
format = format_begun_at;
size_t len = strlen(format);
if (maxrem < len) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(format, len))
return -1;
written += len;
format += len;
}
}
va_end(parameters);
return written;
}
</syntaxhighlight>
==== libc/arch/i386/make.config ====
<
ARCH_CFLAGS
ARCH_CPPFLAGS
KERNEL_ARCH_CFLAGS
KERNEL_ARCH_CPPFLAGS
ARCH_FREEOBJS
ARCH_HOSTEDOBJS
</syntaxhighlight>
==== libc/.gitignore ====
<pre>
*.a
*.d
*.o
</pre>
Line 1,015 ⟶ 1,056:
==== build.sh ====
<
#!/bin/sh
set -e
Line 1,021 ⟶ 1,062:
for PROJECT in $PROJECTS; do
(cd $PROJECT && DESTDIR="$
done
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x build.sh
</syntaxhighlight>
==== clean.sh ====
<
#!/bin/sh
set -e
Line 1,038 ⟶ 1,079:
for PROJECT in $PROJECTS; do
(cd $
done
rm -
rm -
rm -
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x clean.sh
</syntaxhighlight>
==== config.sh ====
<
SYSTEM_HEADER_PROJECTS="libc kernel"
PROJECTS="libc kernel"
Line 1,074 ⟶ 1,115:
# Configure the cross-compiler to use the desired system root.
export
export CC="$CC --sysroot=$SYSROOT"
# Work around that the -elf gcc targets doesn't have a system include directory
# because
if echo "$HOST" | grep -Eq -- '-elf($|-)'; then
export CC="$CC -isystem=$INCLUDEDIR"
fi
</syntaxhighlight>
==== default-host.sh ====
<
#!/bin/sh
echo i686-elf
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x default-host.sh
</syntaxhighlight>
==== headers.sh ====
<
#!/bin/sh
set -e
. ./config.sh
mkdir -p
for PROJECT in $SYSTEM_HEADER_PROJECTS; do
(cd $PROJECT && DESTDIR="$
done
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x headers.sh
</syntaxhighlight>
==== iso.sh ====
<
#!/bin/sh
set -e
Line 1,132 ⟶ 1,174:
EOF
grub-mkrescue -o myos.iso isodir
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x iso.sh
</syntaxhighlight>
==== qemu.sh ====
<
#!/bin/sh
set -e
Line 1,147 ⟶ 1,189:
qemu-system-$(./target-triplet-to-arch.sh $HOST) -cdrom myos.iso
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x qemu.sh
</syntaxhighlight>
==== target-triplet-to-arch.sh ====
<
#!/bin/sh
if echo "$1" | grep -Eq 'i[[:digit:]]86-'; then
Line 1,163 ⟶ 1,205:
echo "$1" | grep -Eo '^[[:alnum:]_]*'
fi
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x target-triplet-to-arch.sh
</syntaxhighlight>
==== .gitignore ====
Line 1,187 ⟶ 1,229:
the source tree by invoking:
<
./clean.sh
</syntaxhighlight>
You can install all the system headers into the system root without relying on
Line 1,195 ⟶ 1,237:
[[Hosted GCC Cross-Compiler]], by invoking:
<
./headers.sh
</syntaxhighlight>
You can build a bootable cdrom image of the operating system by invoking:
<
./iso.sh
</syntaxhighlight>
It's probably a good idea to create a quick ''build-and-then-launch'' short-cut
like used in this example to run the system in your favorite emulator quickly:
<
./qemu.sh
</syntaxhighlight>
== Troubleshooting ==
If you receive odd errors during the build, you may have made a mistake during manual copying, perhaps missed a file,
== Moving Forward ==
Line 1,241 ⟶ 1,283:
Early is not too soon to think about security and robustness. You can take advantage of the optional stack smash protector offered by modern compilers that detect stack buffer overruns rather than behaving unexpectedly (or nothing happening, if unlucky).
=== Going Further ===
{{Main|Going Further on x86}}
This guide is meant as an overview of what to do, so you have a kernel ready for more features, without actually redesigning it radically when adding them.
=== User-Space ===
Line 1,247 ⟶ 1,293:
user-space and an [[OS Specific Toolchain]] that fully utilizes the system root.
== Forum Posts ==
* [[topic:36584|A link error found & fixed]]
[[Category:Tutorials]]
[[Category:C]]
|