The newest Ubuntu release 10.10, codenamed Maverick Meerkat, includes an ARM cross-compiler in the package gcc-arm-linux-gnueabi. This compiler is a welcome addition (thanks to the maintainer Marcin Juszkiewicz and to the Linaro team) to the default repositories, and it is in line both with the Ubuntu roadmap to appear also on ARM-based devices and with the ARM roadmap to appear also on server solutions.
The main purpose of the package is to allow cross-compiling of Linux programs for Ubuntu ARM distributions, but it can be used also for bare metal programming. One thing to be aware is the fact that the compiler by default tries to link the Linux standard C libraries that in bare metal programming have no use.
I’m writing a simple “Hello World” program just like the one I used for my previous post: Hello world for bare metal ARM using QEMU, only this time for the Versatile Platform Baseboard for Cortex-A8, that can be emulated by QEMU too. The requisites are Ubuntu 10.10, the cross-compiler and the QEMU arm emulator that can be installed with the command:
$ sudo apt-get install gcc-arm-linux-gnueabi qemu-kvm-extras
The memory map for the board is specified in its manual; in particular, the first UART is at address 0x10009000
. I modified the “test.c
” code that sends the string “Hello World!” to the UART, using the correct address:
volatile unsigned int * const UART0DR = (unsigned int *)0x10009000; void print_uart0(const char *s) { while(*s != '\0') { /* Loop until end of string */ *UART0DR = *s; /* Transmit char */ s++; /* Next char */ } } void c_entry() { print_uart0("Hello world!\n"); }
The first code to be executed is written in “startup.s
” like in the last example.
.global _Reset _Reset: LDR sp, =stack_top BL c_entry B .
It initializes the stack pointer to a value that is given inside the linker script, and then jumps to the c_entry
function. The linker script is the following:
SECTIONS { . = 0x10000; .ro : { startup.o (.text) *(.text) *(.rodata) } .rw : { *(.data) *(.bss) *(COMMON) } . = ALIGN(8); . = . + 0x1000; /* 4kB of stack memory */ stack_top = .; }
The linker scripts separates two sections of the program: a read-only section containing the code and the constants, and a read-write section containing the data. The 0x10000
address is the place where QEMU puts the code and starts executing. To create the ELF executable, the commands are:
$ arm-linux-gnueabi-gcc -mcpu=cortex-a8 -c -o test.o test.c $ arm-linux-gnueabi-as -mcpu=cortex-a8 -o startup.o startup.s $ arm-linux-gnueabi-gcc -nostdlib -T test.ld -Xlinker "--build-id=none" test.o startup.o -o test
The linker phase options are the most important. The “-nostdlib
” option tells the linker to avoid linking the startup files and standard C libraries. I needed to specify the “--build-id=none
” options because the compiler placed a section of notes just at the beginning of the code, but since I needed the _Reset
code to be exactly at 0x10000
, it ruined the program execution. Instead of using GCC as a frontend, the linker can be invoked directly with the following command, with the same results:
$ arm-linux-gnueabi-ld -T test.ld test.o startup.o -o test
To generate a binary suitable for QEMU and emulate the platform, the commands are the following:
$ arm-linux-gnueabi-objcopy -O binary test test.bin $ qemu-system-arm -M realview-pb-a8 -serial stdio -kernel test.bin Hello world!
The cross-compiler can be used in this simple example but, with respect to the CodeSourcery bare metal toolchain, it does not contain the newlib library or the startup code. For more elaborate examples that use the standard C libraries, an implementation of these libraries must be compiled and the correct include directories must be pointed.
Archna
2011/01/04
Kindly provide link to download bare C Cross compiler.
Balau
2011/01/04
I usually use CodeSourcery G++ Lite for ARM EABI.
Arunkumar V
2011/08/08
Hi Balau,
I tried the above post and used arm-none-eabi- toolchain. I changed the c_entry like this,
void c_entry() {
while(1)
{
print_uart0(“Hello world!\n”);
}
}
and this is my Makefile
test:test.o startup.o test.ld
arm-none-eabi-gcc -g -nostdlib -T test.ld -Xlinker “–build-id=none” test.o startup.o -o test
test.o: test.c
arm-none-eabi-gcc -g -mcpu=cortex-a8 -c -o test.o test.c
startup.o: startup.s
arm-none-eabi-as -g -mcpu=cortex-a8 -o startup.o startup.s
clean:
rm -rf *.o test
I emulated using qemu
qemu-system-arm -M realview-pb-a8 -serial stdio -s -S -kernel test -gdb tcp::43333
and in another Terminal I started the gdb
arm-none-eabi-gdb test
(gdb) target remote localhost 43333
But qemu keeps on printing “Hello World”. In the gui it is showing that Qemu[stopped]. As I have given S option in Qemu, it should stop looping. Could you please help me with the correct options for qemu.
Balau
2011/08/08
Your options “-s” and “-gdb tcp::43333” are contrasting, because “-s” is a shorthand for “-gdb tcp::1234”, but I think this is not the problem.
Some Ubuntu versions of qemu-system-arm do not work well with the “-S” options or debugging in general.
I suggest recompiling QEMU from source and see if something changes.
One example on how to compile qemu-system-arm from source is here: https://balau82.wordpress.com/2010/08/17/debugging-arm-programs-inside-qemu/
Arunkumar V
2011/08/09
recompiling QEMU worked :). Thanks
jsolmen
2011/09/06
Hi Balau,
I got the following linker error (using CodeSourcery 2011.03 toolchains):
test.o:(.ARM.exidx+0x0): undefined reference to `__aeabi_unwind_cpp_pr0′
I had to use the arm-none-eabi- toolchain to get this linked.
Thanks for sharing your experiences, great blog!
Juan.
Balau
2011/09/06
The
__aeabi_unwind_cpp_pr0
function should be called by code that can lead to “exceptions” such as divisions by 0. If you don’t care what happens after something like that, you can implement yourself an empty function with that name like U-Boot did.Gonzalo
2011/11/22
Hello Balau,
Your post helped me a lot, thank you. In the last paragraph you pointed out the need of newlib as a basic library. I’m trying to compile it withUbuntu’s arm-linux.gnueabi-gcc but it I’m not sure whether I need extra config options or the same you used on your post ‘using newlib in arm…’. Is this correct?:
./configure –target arm-none-eabi –disable-newlib-supplied-syscalls
Shoud I include “-nostdlib” or “–build-id=none” ?
It compiles OK without these last options, nevertheless.
Thank you!
Balau
2011/11/22
When you compile Newlib you create a library, usually static. The “-nostdlib” and “-build-id=none” are not relevant when you compile Newlib because these options are used to link a complete bare metal executable.
When you compile and link an executable together with Newlib you are providing a standard library, but you should anyway use -nostdlib to avoid that the compiler uses its own standard libraries, and then provide the path to Newlib libraries. “-build-id=none” should still be provided for the Ubuntu ARM cross-compiler.
You say you are using Ubuntu arm-linux-gnueabi-gcc but in your configure command you are passing “arm-none-eabi”, which means you are compiling Newlib with the arm-none-eabi-gcc compiler. If you are using arm-none-eabi the “-build-id=none” should not be necessary when creating an executable.
Gonzalo
2011/11/26
Thank you for your reply, Balau.
You’re right, I wrote it wrong. I used “arm-linux-gnueabi-gcc” instead as I haven’t CodeSourcery installed.
Your post was very helpful.
Thank you so much.
makeupbytiffanyd
2012/11/27
Do you mind if I quote a couple of your articles as long as I
provide credit and sources back to your weblog? My blog
site is in the exact same area of interest as yours and my users would certainly benefit from a lot of
the information you present here. Please let me know if this alright with you.
Many thanks!
Balau
2012/11/27
I don’t mind that my articles are quoted or re-blogged, as long as the terms of the terms of the Creative Commons Attribution-Share Alike 3.0 License are respected.
ravi
2012/11/29
I’ve executed successfully all the way to
$ qemu-system-arm -M realview-pb-a8 -serial stdio -kernel test.bin
Then I get a blank QEMU terminal.
Not Hello world!
Balau
2012/11/29
I suggest one of two things to debug the problem:
– running QEMU with “-d in_asm,cpu -D ./qemu.log -singlestep” options, to make it generate a (big) log that can help you trace what happens
– running QEMU with “-s -S” options and attaching with arm-linux-gnueabi-gdb, using “target remote localhost:1234″ and debugging with that.
ravi
2012/11/29
Thanks Balau for a quick response. After executing your first command, this was the response
qemu-system-arm: -D: invalid option
If this is fixed I suppose I’ll get qemu.log and I can parse thru’ the log.
Balau
2012/11/29
This seems to be a problem in your QEMU version because the option is clearly described in the –help and it always worked for me. I see from the help that the default log location is in “/tmp/qemu.log” so it may be possible that you are able to see the log at that path if you don’t add the “-D ./qemu.log” option.
ravi
2012/11/29
Yes, I do see /tmp/qemu.log.without using -D option. But this file has nothing in it.
After I execute without -D option, I get the following on the screen
>qemu-system-arm -M realview-pb-a8 -d in_asm assembly -singlestep -s stdio -kernel test.bin
qemu-system-arm: -s:drive with bus=0, unit=0 (index=0) exists
>
dmitrywrk
2013/03/24
hi! many thanks for this post. Can you help with rigth option for arm926 (or the best way armv5te without java instr.)? Mainly, want to have “bare metall cross-compiler for spmp8000” :-)(core arm926)?
Balau
2013/03/24
I’m not familiar with the spmp8000, but I think “-mcpu=arm926ej-s” should be the option you want to use. Java machine code won’t be inserted by GCC anyway.
If you follow the instructions on how to build your own toolchain, found in the spmp8000 wiki, you probably will not need the option, but I think it’s a more complex way:
http://alemaxx.al.funpic.de/spmp8000/sp8hc.html
http://paklids.blogspot.it/2010/06/arm-toolchain-for-libspmp8000.html
Maybe it’s better to try different toolchains, like Emdebian, before rebuilding your own.
dmitrywrk
2013/03/24
Thank you for such a quick response. Trying to compile toolchain arm-none-eabi http://www.kunen.org/uC/gnu_tool.html (try new version too) but it fell out with an error when compiling gcc(binutils compiling with warning,but no errors). One of bug report say that it works if GCC compile from scratch (for [b]ubuntu[/b])
so I would like to use ubuntu arm-linux-gnueabi + static newlib.That is why like this post.
P.s. sorry for my english. Thanks again
techpedia
2014/03/14
Do you mind if I quote a few of your posts as long as I provide
credit and sources back to your blog? My blog site is in the exact same niche as yours
and my users would genuinely benefit from a lot of the information you present here.
Please let me know if this alright with you.
Appreciate it!
Balau
2014/03/14
Sure, as written at the bottom of the sidebar I license the content of this blog with Creative Commons Attribution-Share Alike 3.0 License, so a simple solution is to add at the beginning (or at the end) of your re-blog the following line, substituting the “Freedom Embedded” link with the link to page you re-blogged:
Source: Freedom Embedded by Francesco Balducci, license CC BY-SA 3.0.
Wei Xu
2014/04/01
Thank you very much. It is very useful!
I try to use the program with the vexpress-a15, modify the UART0 address to 0x1c090000, it seems not work.
But I also try this with the vexpress-a9 with UART0 address 0x10009000, it is successful.
Is there some difference in the vexpress-a15?
Balau
2014/04/02
I don’t know these machines directly, but it seems in QEMU source code that you are using the right address: hw/arm/vexpress.c
Try to run QEMU with
-s -S
options , attach with arm gdb and execute your program step-by-step.You can also run QEMU adding options
-d in_asm,cpu -singlestep -D ./qemu.log
to trace what happens into./qemu.log
.