Writing a Simple Operating System — from Scratch

(Jeff_L) #1

CHAPTER 5. WRITING, BUILDING, AND LOADING YOUR


KERNEL 59


# Run bochs to simulate booting of our code.
run: all
bochs

# This is the actual disk image that the computer loads
# which is the combination of our compiled bootsector and kernel
os-image: boot/boot_sect.bin kernel.bin
cat $^ > os -image

# This builds the binary of our kernel from two object files:
# - the kernel_entry , which jumps to main() in our kernel
# - the compiled C kernel
kernel.bin: kernel/kernel_entry.o ${OBJ}
ld -o $@ -Ttext 0x1000 $^ --oformat binary

# Generic rule for compiling C code to an object file
# For simplicity , we C files depend on all header files.
%.o : %.c ${HEADERS}
gcc -ffreestanding -c $< -o $@

# Assemble the kernel_entry.
%.o : %.asm
nasm $< -f elf -o $@

%.bin : %.asm
nasm $< -f bin -I ’../../16 bit/’ -o $@

clean:
rm -fr *.bin *.dis *.o os-image
rm -fr kernel /*.o boot /*.bin drivers /*.o

5.4 C Primer


C has a few quirks that can unsettle a new programmer of the language.


5.4.1 The Pre-processor and Directives


Before a C file is compiled into an object file, a pre-processor scans it for pre-processor
directives and variables, and then usually substitutes them with code, such as macros
and values of constants, or with nothing at all. The pre-processor is not essential for
compiling C code, but serves rather to offer some convenience that makes the code more
managable.


#define PI 3.141592
...
float radius = 3.0;
float circumference = 2 * radius * PI;
...

The pre-processor would output the following code, ready for compilation:

Free download pdf