Really great and very detailed series of artistic work on ARM and emulation.
Posted by Balau on Dec 16 of 2010.
When dealing with embedded software, I often find useful to have the standard C functions we all learn during our first programming course: printf, malloc, getchar, strncpy, …
A common way to have them is using Newlib. Newlib is an implementation of the standard C library that is specifically thought to run somewhere with low resources and undefined hardware. The idea of Newlib is to implement the hardware-independent parts of the standard C library and rely on few low-level system calls that must be implemented with the target hardware in mind.
I compiled Newlib with the CodeSourcery ARM compiler for bare-metal targets: Sourcery G++ Lite 2010.09-51. Once the toolchain is installed, the commands I used to download compile Newlib are:
$ wget ftp://sources.redhat.com/pub/newlib/newlib-1.18.0.tar.gz
$ tar xzf newlib-1.18.0.tar.gz
$ cd newlib-1.18.0/
$ ./configure --target arm-none-eabi --disable-newlib-supplied-syscalls<
$ make
$ cd ..
The “--disable-newlib-supplied-syscalls” option is necessary because otherwise Newlib compiles some pre-defined libraries for ARM that are useful in conjunction with debug features such as the RDI monitor. Many different outputs are compiled inside the arm-none-eabi subdirectory, but in particular the “libc.a” archive in the newlib directory is the one I use.
As an example, I want to compile the following “test.c” program:
#include
#includeextern char *heap_end; /* Defined in syscalls.c */
void c_entry() {
char c;
char *ptr = NULL;
size_t alloc_size = 1;
do {
c =getchar();
printf(“%d: %c\n”, c, c);
ptr = realloc(ptr, alloc_size);
if(ptr == NULL) {
puts(“Out of memory!\nProgram halting.”);
for(;;);
} else {
printf(“new alloc of %d bytes at address 0x%X\n”, alloc_size, (unsigned int)ptr);
alloc_size <<= 1;
printf("Heap end = 0x%X\n", (unsigned int)heap_end);
}
} while (1);
}
The program uses standard input/output functions and allocates more and more memory with realloc, printing some information to understand what’s going on. The idea is to use the UART serial port as the input/output, and monitor how the memory is managed. The heap_end variable is something that I will implement and use later to manage the memory allocation.
The program needs at least some basic starting code “startup.s” that I borrow from a previous example of mine about the hello word bare metal qemu post:
LDR sp, =stack_top
BL c_entry
B .
And the linker script “test.ld” again is a modified version from the hello word bare metal qemu post:
SECTIONS
{
. = 0x10000;
.ro : {
startup.o (.text)
*(.text)
*(.rodata)
}
.rw : {
*(.data)
*(.bss)
*(COMMON)
}
. = ALIGN(8);
heap_low = .; /* for _sbrk */
. = . + 0x10000; /* 64kB of heap memory */
heap_top = .; /* for _sbrk */
. = . + 0x10000; /* 64kB of stack memory */
stack_top = .; /* for startup.s */
}
more
more
and more
more