Skip to content

Instantly share code, notes, and snippets.

@JShorthouse
Last active February 25, 2024 01:44
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JShorthouse/bfe49cdfad126e9163d9cb30fd3bf3c2 to your computer and use it in GitHub Desktop.
Save JShorthouse/bfe49cdfad126e9163d9cb30fd3bf3c2 to your computer and use it in GitHub Desktop.
Compiling GBA programs on Linux with GCC

Compiling GBA programs on Linux with GCC

There is a strange lack of guides and tools online for compiling Gameboy Advance homebrew programs on Linux. I didn't want to use devkitpro - their installation method of requiring you to use a forked version of pacman is extemely strange and I didn't want to install all of that on my system just to complile some programs.

The only other guides I found for Linux were this one and this one which both involve compiling custom versions of GCC and assosicated libraries. This lead me down a road of pain, after spending multiple hours fixing compiler errors only to create new errors I gave up. I thought that their had to be a simpler way, and there is!

The solution

Debian already has a version of GCC that can compile ARM programs in the repos, no manual compiling necessary! The package is called arm-none-eabi-gcc.

sudo apt install arm-none-eabi-gcc

After installing you will need to download this example project (it's from one of the guides I linked earlier).

The structure of this project is as follows:

.
├── crt0.s
├── example.c
├── lnkscript
└── Makefile

From this we need lnkscript (a script used for linking) and crt0.s which contains setup routines. Both of these files were created by Jeff Frohwein (original code here).

We won't be using the Makefile, although I used it to determine the necessary compiler flags. If you want to use the makefile it will need to be adapted because the path for GCC and other utilities won't be correct.

Let's try compiling the example.c program. If compiled correctly it should turn the screen red.

When compiling we need to include both our program and crt0.s, as well as a bunch of flags. The full command is:

arm-none-eabi-gcc crt0.s example.c -mcpu=arm7tdmi -nostartfiles -Tlnkscript

We can then run our program using the mGBA emulator. If you don't have that installed it's very simple:

sudo apt install mgba-sdl

And then:

mgba a.out

And you should see a red screen.

Now you can compile and run GBA programs and you didn't have to build any software from source or install pacman!

(edit) "Fixing" the resulting program

While the executable that GCC spits out from the above steps will run in most emulators, it won't run on actual harware. We need to strip the binary and "fix" the header so that the checksums that the GBA checks are correct.

Stripping the binary is simple, using the objcopy version also included in the gcc-arm-none-eabi package.

arm-none-eabi-objcopy -O binary <input> <output>

So lets run

arm-none-eabi-objcopy -O binary a.out a.gba

We then need to use a simple header fixing tool. gbafix is a simple, single C file tool from devkit pro and there is also Header Tool (ht.pl), a simple perl script. I don't know which is better but I will use header tool here because it also allows you to check if the headers are correct.

Lets check our binary:

./ht.pl -cl a.gba
rom name : 
logo: ok!
checksum: ok!

In this case our headers are fine! crt0.s seems to handle setting them correctly for us. I am not sure if they will always be set correctly, or if there will be cases where they need to be fixed. Almost every guide I've looked at explicitly mentions the need to manually fix headers so I might as well explain it here incase it ever is needed.

It's extemely simple. With gbafix:

./gbafix a.gba

(overwrites the original file)

With ht.pl

./ht.pl -clo fixed.gba a.gba

You can also use these tools to set various metadata. Not sure if any of it is used by the GBA but apparently some emulators read it.

Your program is now theoretically capable of running on real harware, although I don't have a flash cart or link cable to actually confirm this. Please let me know if you do manage to do this or if extra steps were needed.

@flabbergast
Copy link

flabbergast commented Feb 25, 2021

I can confirm: your example runs on a real hardware (GBA) from a flash cart (an actual flash cart, not everdrive/ez flash/...), doesn't even need "fixing". However this simple program (also compiled your way) runs in an emulator, but not on a real hardware without "fixing". After fixing, it does.
(NB. The ht.pl link is broken now.) Thank you for this writeup!

@JShorthouse
Copy link
Author

Thanks for the feedback, glad to hear it worked with a real cart! I actually bought an ezflash clone shortly after writing this up (specifically a "super card sd") and can confirm it works on real hardware that that too.

I've mirrored the ht.pl code to a gist and updated the link.

I also have a backup of the example project so if someone is reading this in the future and that link is down please let me know and I can mirror that too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment