# Getting Rust on the GBA 3

Posted on November 21, 2015

Alright, I have removed the remaining C code from the project. This was an adventure.

I followed the advice from pragmatic bare metal rust, and emitted both an .rlib and a .o file for the core library with:

rustc --target=target.json -Z no-landing-pads ../rust/src/libcore/lib.rs --out-dir libs/ --emit link,obj

Also, I’ve removed landing pads, since we are not going to be recovering from panics at all.

I switched from a -o flag to --out-dir, as we output both libcore.rlib and core.o.

Then, when compiling rust-gba.rs, I also request an object file

rustc -L libs -Z no-landing-pads --target=target.json --emit obj  rust-gba.rs

We still link everything together with clang.

clang -nostdlib -target arm-none-eabi -Tgba_cart.ld \
-Wl,--gc-sections \
rust-gba.o libs/core.o \
gba_crt0.o crti.o -o rust-gba.elf

arm-none-eabi-objcopy -O binary rust-gba.elf rust-gba.gba
gbafix rust-gba.gba

But, we also need to pass --gc-sections to the linker, hence -Wl,--gc-sections. Otherwise, we need to have floating point support, as core defines f32 and f64, which we don’t have hardware support for on the GBA. We get a ton of linker errors otherwise, this way we only get one:

ld: section .got loaded at [08004a18,08004a23] overlaps section .pad loaded at [08004a18,08004a1f]

The .got section is the Global Offset Table, and the PLT is the Procedure Linkage Scheme Table. These are used when there is some dynamic linking going on, which is a little odd, since I am attempting to statically link everything into one gba file, but ok compiler if you really want to have them, I can give you some bytes in the ROM.

The gba_cart.ld file already placed .plt in rom, but forgot about .got, so simply adding it fixed the problem.

EDIT: Luqman pointed out that adding

	"relocation-model"    : "static",

to the target.json prevents rustc from trying to produce those segments at all, which is a far better solution.

Now, more excitingly I can write readable code, and less of this magic constants as addresses business.

#![feature(lang_items, no_std)]

#![no_std]
#![crate_type = "staticlib"]

Now, this time we use no_std instead of no_core, and we automatically have extern crate core added for us. Also, things link best if I say crate_type = "staticlib".

#[lang = "panic_fmt"]
pub extern fn panic_fmt() -> ! { loop {} }

#[lang = "stack_exhausted"]
pub extern fn stack_exhausted() -> ! { loop {} }

#[lang = "eh_personality"]
pub extern fn eh_personality() -> ! { loop {} }

Someday, I will improve panic_fmt, and throw something up on the screen when everything goes wrong. Till then, just loop forever on crash.

// // I'm not 100% sure what this function does, but references to it are compiled
// // into the program by the Rust compiler. I think it would be called in the case
// // of a program panic.
#[no_mangle]
pub fn __aeabi_unwind_cpp_pr0() {
loop {}
}
#[no_mangle]
pub fn __aeabi_unwind_cpp_pr1() {
loop {}
}

Now there’s two of these strange functions. I don’t think we’re going to be unwinding anytime soon.

mod gfx;

use gfx::Color;

Oh, what’s this, a second file? Nice. Lets take a look in there before finishing the main file.

use core::slice;

pub struct Color (u16);

impl Color {
//! Creates a color with 16 bits, 5 bits for each channel.
pub fn rgb15(red: u32, green: u32, blue: u32) -> Color {
Color((red | (green << 5) | (blue << 10)) as u16)
}
}

Cool, a nice way to create colors. And since the name is rbg15, I can hardly forget the order of arguments.


/// Check out http://www.coranac.com/tonc/text/bitmaps.htm for more details on
/// different modes.
///
/// Mode3 is a one buffer, with width 240, height 160, and 16 bits per pixel (bpp).
/// Is it the most basic of modes.
pub struct Mode3;

impl Mode3 {
/// Calling this invalidates all other modes and enters Mode3.
pub fn new () -> Mode3 {
unsafe {
*(0x04000000 as *mut u32)= 0x0403;
}
Mode3
}

/// Draw a dot at co-ordinates (x, y), and of color color.
pub fn dot(&mut self, x: u32, y: u32, color: Color) {

assert!(x < 240);
assert!(y < 160);

let buff : &mut [u16] = unsafe {
slice::from_raw_parts_mut(0x06000000 as *mut u16, 240 * 160)
};
buff[(x+y*240) as usize] = color.0;
}
}

Back to the main file rust-gba.rs, and see how this gets put to use:


#[no_mangle]
pub extern "C" fn main() {
let mut m = gfx::Mode3::new();
m.dot(120, 80, Color::rgb15(31, 0, 0));
m.dot(136, 80, Color::rgb15(0, 31, 0));
m.dot(120, 96, Color::rgb15(0, 0, 31));
}

This is pretending to be the main from that C file still, but it works, so that’s fine with me.

I’m about ready to try and pull things out into a separate crate for the library code and main, but work out a few more of TONC’s examples first.

Well, you can check out the rest of the files on github now.

See you next time.