Now that you have your project structure, let’s take a look at the tools we will use to create our final image.
As discussed earlier, I use the arm-none-eabi-* compiler. This is a “tool chain” which means if you followed my download instructions, you will have a variety of different programs that all start with that prefix. This tool chain includes a C Compiler, C++ Compiler, Assembly Compiler, Dis-assembler, and a few other things. So how the heck do we get access to all that neat stuff? Well, it’s pretty complicated and well documented. To setup your environment, I recommend following some of this tutorial: http://hertaville.com/2012/09/28/development-environment-raspberry-pi-cross-compiler/
NOTE: That post shows you how to install a different tool chain than I use. You can try it if you want, but the important thing to glean from that site is the PATH setup instructions for pointing your local PATH variable to the compiler bin directory. Please note you’ll have to do this for the root user as well – if you plan on compiling under root.
I’m going to assume you have the compiler setup and configured properly. So how do we actually use it? Well, let’s start by creating a program! Now I don’t intend to teach you assembly language, but I do want to show you the basics of how to use the compiler. Plus, the entry point for our kernel has to be assembly. So you will learn a tiny bit about it. Let’s start by creating a new file called init.asm within our /project/kernel/ directory. I’ll post a screenshot of my code and step you through it.
Okay, that is technically assembly but it doesn’t look too scary.
- .global – This is basically defining a function that we plan to implement later on which can be linked by the compiler and called from other files. I don’t think it actually has to be global, in this case, but I wanted to show you the code anyway.
- _start: – This line defines what we call a “label”. Labels are basically functions.
- MOV sp,#0x8000 – In assembly, there are many “global” variables that you have access to. sp means “stack pointer”, I believe. What this line of code does is specify a location in memory where the stack memory will start to be allocated. It is pretty much required to be the first thing in your program.
- b hang – This is two things. First, ‘b’ means ‘branch’ (essentially “call function”). There are multiple ways to call a function and I am not entirely sure of the difference between them. ‘bx’ means “branch and then return”, I think. So ‘b’ probably means you’re going away but you aren’t planning on returning!
- hang: – Again, this just defines a new function called ‘hang’.
- b hang – Again, this just calls the function ‘hang’ thus putting us in an infinite loop.
And that’s it! So now that we have a lovely program, how do we compile it specifically for the raspberry pi? Well, before we jump ahead of ourself, let’s take a look at some of the tools that our tool chain provides us.
Here is a list of some really useful commands and their descriptions:
This utility is capable of disassembling the output of your compiled files (amongst many other things). Use the -D flag to tell it to disassemble.
This utility is used to copy binary files (and possibly preform transformations on them in the process). We use it to copy our linked program into an IMG file.
This is the assembler. We will be using it to compile the bootstrap.S file into a common format that can eventually be linked with C/C++.
This is the C compiler. There are a number of flags we’ll be talking about later which we will be using during our compilation. NOTE: if you change that last part to g++ it comes a C++ compiler. All the same command line switches are the same.
And finally our linker! This is what takes all of the compiled binaries that we’ve developed and merges them into one output. There are some very important command line switches we need to learn about to properly use this one. So I’ll be explaining those in the next section.
The BUILD Script
Technically you’re supposed to use makefiles, but I prefer bash scripting. So let me show you a possible build.sh script looks like and we will go over some of the options.
#!/bin/sh compiler=arm-none-eabi code=../code boot=../boot # First let's compile our assembly file. $compiler-as $code/init.asm -o $code/init.o # Then let's call the linker to generate a binary output. $compiler-ld $code/init.asm -o $code/kernel.elf # Then let's dump some debug info to disk. $compiler-objdump -D $code/init.o > $code/init.disassembled.asm $compiler-objdump -D $code/kernel.elf > $code/kernel.disassembled.asm # Lastly let's copy our binary into an img format. $compiler-objcopy $code/kernel.elf -O binary $boot/kernel.img echo "Finished compiling!"
Using the script above, your program should be compiled, disassembled, linked, converted to an IMG file, and then copied to the boot directory! If you just move all the files in that boot directory onto a FAT32 formatted SD Card (or just call that make image script we made in the other post) and you’ll be good! Give it a whirl.
DISCLAIMER: I wrote this code by hand without testing it. I will be doing some tests later (at which point I’ll remove this disclaimer). So be aware that I may have made a mistake somewhere. Feel free to post questions as they arise.