Region ram overflowed and section .text will not fit region ram - c

I'm trying to compile a bare-metal app with GCC compiler (Standard C). I use Cyclone V SoC with Cortex-A9 processor. Eclipse DS-5. I get these errors - "Region ram overflowed by 295376 bytes" and "section .text will not fit region ram". I think that the problem isn't in the linker script but in something else. I see messages that compiler tries to add all my .c files in project into one .axf file even if I include none of them in my main .c file (where I write the program) When I delete some unused .c files from project it says "Region ram overflowed by 275433 bytes" (different overflow size). What should I do to get rid of this mistake?

flash.ld
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 0x100
}
SECTIONS
{
.text : { *(.text*) } > ram
.rodata : { *(.rodata*) } > ram
.bss : { *(.bss*) } > ram
}
flash.s
.globl _start
_start:
b reset
b hang
b hang
b hang
b hang
b hang
b hang
b hang
reset:
mov sp,#0x8000
bl notmain
b hang
hang:
b hang
notmain.c
unsigned int data[1000];
int notmain ( void )
{
unsigned int ra;
for(ra=0;ra<1000;ra++) data[ra]=ra;
return(0);
}
Makefile
ARMGNU = arm-none-eabi
COPS = -O2 -nostdlib -nostartfiles -ffreestanding
all : notmain.bin
clean:
rm -f *.bin
rm -f *.o
rm -f *.elf
rm -f *.list
flash.o : flash.s
$(ARMGNU)-as $(AOPS) flash.s -o flash.o
notmain.o : notmain.c
$(ARMGNU)-gcc $(COPS) -c notmain.c -o notmain.o
notmain.bin : flash.ld flash.o notmain.o
$(ARMGNU)-ld -o notmain.elf -T flash.ld flash.o notmain.o
$(ARMGNU)-objdump -D notmain.elf > notmain.list
$(ARMGNU)-objcopy notmain.elf notmain.bin -O binary
output:
arm-none-eabi-ld -o notmain.elf -T flash.ld flash.o notmain.o
arm-none-eabi-ld:flash.ld:10: warning: memory region `rom' not declared
arm-none-eabi-ld: notmain.elf section `.bss' will not fit in region `ram'
arm-none-eabi-ld: region `ram' overflowed by 3828 bytes
Makefile:21: recipe for target 'notmain.bin' failed
make: *** [notmain.bin] Error 1
I could have made it say .text wont fit, but it is the same problem you are having. Change the size in the linker script.
ram : ORIGIN = 0x00000000, LENGTH = 0x1000
and now it is happy
arm-none-eabi-ld -o notmain.elf -T flash.ld flash.o notmain.o
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy notmain.elf notmain.bin -O binary
The .text section, which is your program itself basically, was too big for the "memory" allocated for it. If the linker script you are using reflects the true size of what you are allocated, your program is too big you need to make it smaller, can start by optimizing if you are not (-O2 on the gcc command line) or putting static in front of functions that are not global, or just overall reducing the amount of code by cleaning up. that doesnt mean make a few lines of C into one long line of C with no real functionality removed, you need to have it do fewer things.
Or as in my case here perhaps you have some .data or .bss or other items that are also in the same section defined in the linker script and the combination of all of them are taking up too much space. Changing the length to 0x10 in my example above it complains about .text first without the others, as above if I make it 0x100 it complains about .bss then stops complaining, so ld is complaining about the one that actively crosses the line not the ones that didnt get pulled in yet.
You can make the length larger to get it to build, then examine the elf file (objdump or readelf or whatever) and from there perhaps get an idea of what part is really too big, what functions are huge or what data, etc. Functions that are global that dont need to be that are being inlined by the optimizer, etc.

Related

GDB-remote + qemu reports unexpected memory address for static C variable

Remote debugging a code running in Qemu with GDB, based on an os-dev tutorial.
My version is here. The problem only happens when remote-debugging code inside qemu, not when building a normal executable to run directly inside GDB under the normal OS.
Code looks something like this:
#define BUFSIZE 255
static char buf[BUFSIZE];
void foo() {
// Making sure it's all zero.
for (int i = 0; i < BUFSIZE; i++) buf[i] = 0;
// Setting first char:
buf[0] = 'a';
// >> insert breakpoint right after setting the char <<
// Prints 'a'.
printf("%s", buf);
}
If I place a breakpoint at the marked spot and print the buffer with p buf I get random values from random places, seemingly from my code section. If I get the address by p &buf I get something that does not look correct, for two things:
If I do a char* p_buf = buf and I check the address with p p_buf it gives me a totally different address, which is stable across executions (the other was not). Then I inspect that memory section with x /255b 0x____ and I can see the a and then zeros (97 0 0 0 ... 0).
The next command (printf("%s", buf);) does actually prints a.
This leaves me believing it might be GDB not knowing the correct location if I only inspect the static variable.
Where should I start debugging this?
Details about the compile conditions:
Compile flags: -g -Wall -Wextra -pedantic -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs -m32
qemu-system-i386
Gcc: i386 elf target
Example output from GDB:
(gdb) p buf
$1 = "dfghjkl;'`\000\\zxcvbnm,./\000*\000 ", '\000' <repeats 198 times>...
(gdb) p p_buf
$2 = 0x40c0 <buf+224> "a"
(gdb) p &buf
$3 = (char (*)[255]) 0x3fe0 <buf>
(gdb) info address buf
Symbol "buf" is static storage at address 0x3fe0.
Update 2:
Disassembled a version of the code that shows the discrepancy:
; void foo
0x19f1 <foo> push %ebp
0x19f2 <foo+1> mov %esp,%ebp
0x19f4 <foo+3> sub $0x10,%esp
; char* p_buf = char_buf; --> `p &char_buf` is 0x4040 (incorrect) but `p p_buf` is 0x4100
0x19f7 <foo+6> movl $0x4100,-0x4(%ebp)
; void* p_p_buf = (void*)p_buf; --> `p p_p_buf` gives 0x4100
0x19fe <foo+13> mov -0x4(%ebp),%eax
0x1a01 <foo+16> mov %eax,-0x8(%ebp)
; void* p_char_buf = (void*)&char_buf; --> `p p_char_buf` gives 0x4100
0x1a04 <foo+19> movl $0x4100,-0xc(%ebp)
; char_buf[0] = 'a'; --> correct address
0x1a0b <foo+26> movb $0x61,0x4100
; char_buf[1] = 'b'; --> correct address (asking `p &char_buf` here is still incorrectly 0x4040)
0x1a12 <foo+33> movb $0x62,0x4101
; void foo return
0x1a19 <foo+40> nop
0x1a1a <foo+41> leave
0x1a1b <foo+42> ret
My Makefile for building the project looks like:
C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
C_HEADERS = $(wildcard kernel/*.h drivers/*.h)
OBJ = ${C_SOURCES:.c=.o kernel/interrupt_table.o}
CC = /home/itarato/code/os/i386elfgcc/bin/i386-elf-gcc
# GDB = /home/itarato/code/os/i386elfgcc/bin/i386-elf-gdb
GDB = /usr/bin/gdb
CFLAGS = -g -Wall -Wextra -ffreestanding -fno-exceptions -pedantic -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs -m32
QEMU = qemu-system-i386
os-image.bin: boot/boot.bin kernel.bin
cat $^ > $#
kernel.bin: boot/kernel_entry.o ${OBJ}
i386-elf-ld -o $# -Ttext 0x1000 $^ --oformat binary
kernel.elf: boot/kernel_entry.o ${OBJ}
i386-elf-ld -o $# -Ttext 0x1000 $^
kernel.dis: kernel.bin
ndisasm -b 32 $< > $#
run: os-image.bin
${QEMU} -drive format=raw,media=disk,file=$<,index=0,if=floppy
debug: os-image.bin kernel.elf
${QEMU} -s -S -drive format=raw,media=disk,file=$<,index=0,if=floppy &
${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf" -ex "tui enable" -ex "layout split" -ex "focus cmd"
%.o: %.c ${C_HEADERS}
${CC} ${CFLAGS} -c $< -o $#
%.o: %.asm
nasm $< -f elf -o $#
%.bin: %.asm
nasm $< -f bin -o $#
build: os-image.bin
echo Pass
clean:
rm -rf *.bin *.o *.dis *.elf
rm -rf kernel/*.o boot/*.bin boot/*.o
For me, this doesn't seem to happen:
Breakpoint 1, main () at test65.c:16
16 printf("%s", buf);
(gdb) p buf
$2 = "a", '\000' <repeats 253 times>
Where should I start debugging this?
It seems like there are two things that might go wrong:
1. GDB might be reading from wrong location
I'm not sure what could cause this, but it is easy enough to verify. Check what address p &buf gives you. Then compare it to what you get from p_buf and also to what info address buf shows you.
Note that due to address space layout randomization the address of static variables will change at the point when you start the process. So before run command the address could be e.g. 0x4040 and then change to 0x555555558040 once the code is running:
(gdb) info address buf
Symbol "buf" is static storage at address 0x4040.
(gdb) run
....
Breakpoint 1, main () at test65.c:16
16 printf("%s", buf);
(gdb) p &buf
$1 = (char (*)[255]) 0x555555558040 <buf>
(gdb) info address buf
Symbol "buf" is static storage at address 0x555555558040.
2. GDB is reading correct place, but data is not there yet
It sounds like a typical debugging problem caused by compiler optimizations. For example, the compiler might move the setting of buf[0] = a after the point where your breakpoint lands, though it must set it before printf() gets called. You could try compiling with -O0 to see if it changes anything.
You can also check the disassembly with disas command, to see what has executed up to that point:
(gdb) disas
Dump of assembler code for function main:
0x000055555555517b <+50>: movb $0x61,0x2ebe(%rip) # 0x555555558040 <buf>
=> 0x0000555555555182 <+57>: lea 0x2eb7(%rip),%rsi # 0x555555558040 <buf>
0x0000555555555189 <+64>: lea 0xe74(%rip),%rdi # 0x555555556004
0x0000555555555190 <+71>: mov $0x0,%eax
0x0000555555555195 <+76>: callq 0x555555555050 <printf#plt>
For me the breakpoint lands at the point right after movb sets 0x61 (letter a) to buf.
If you use stepi command until you are at callq printf instruction, you can be sure you see the buffer exactly like printf would see it.
This is an interesting problem. It comes down to the fact that the code generated by LD (linker) for the ELF executable kernel.elf is different from that of the code generated by LD for kernel.bin when using the --oformat binary option. While one would expect these to be the same, they are not.
More simply put these Makefile rules do not produce the same code as you might expect:
kernel.elf: boot/kernel_entry.o ${OBJ}
i386-elf-ld -o $# -Ttext 0x1000 $^
and
kernel.bin: boot/kernel_entry.o ${OBJ}
i386-elf-ld -o $# -Ttext 0x1000 $^ --oformat binary
It appears the difference is in how the linker is aligning the sections when used with and without --oformat binary. The ELF file (and the symbols used for debugging) are seen to be in one place while the binary file that is actually running in QEMU had code and data generated at different offsets.
I hadn't ever observed this issue because I use my own linker scripts and I always generate the binary file from the ELF executable with OBJCOPY rather than using LD to link twice. OBJCOPY can take an ELF executable and convert it to a binary file. The Makefile rules could be amended to look like:
kernel.bin: kernel.elf
i386-elf-objcopy -O binary $^ $#
kernel.elf: boot/kernel_entry.o ${OBJ}
i386-elf-ld -o $# -Ttext 0x1000 $^
Doing it this way will ensure the binary file that is generated matches what was produced for the ELF executable.

Line numbers in GCC output object file not preserved when linking to ELF

I am trying to build a basic project for ARM with symbols and associated line numbers, so that I can easily debug the project from GDB Multiarch while it is running in QEMU.
I have two files, a C source file and some assembly. In this example, they are very simple:
cmain.c:
int add_numbers(int a, int b) {
return a + b;
}
int cmain() {
int a = 3;
int b = 4;
int c = add_numbers(a, b);
}
main.s:
.section .init
.global _start
_start:
.extern cmain
mov sp, #0x8000
bl cmain
Additionally, here's the linker file, kernel.ld:
SECTIONS {
.init 0x8000 : {
*(.init)
}
.text : {
*(.text)
}
.data : {
*(.data)
*(.bss)
*(.rodata*)
*(.COMMON)
}
/DISCARD/ : {
*(*)
}
}
I then build these projects with debugging symbols using the following shell script. In brief, it assembles and compiles the files into object files, then links them into an ELF and objcopies into an IMG.
rm -r build
mkdir -p build
arm-none-eabi-as -I . main.s -o build/main.o
arm-none-eabi-gcc -ffreestanding -fno-builtin -march=armv7-a -MD -MP -g -c cmain.c -o build/cmain.o
arm-none-eabi-ld build/main.o build/cmain.o -L/usr/lib/gcc/arm-none-eabi/6.3.1/ -lgcc --no-undefined -o build/output.elf -T kernel.ld
arm-none-eabi-objcopy build/output.elf -O binary build/kernel.img --keep-file-symbols
For GDB debugger stepping, I need the ELF to have line numbers for the C source. (Note that the actual project has many more C files.) The lines numbers are present in C object file, but not in the ELF.
$ arm-none-eabi-nm build/cmain.o --line-numbers
00000000 T add_numbers /home/aaron/Desktop/arm-mcve/cmain.c:1
00000030 T cmain /home/aaron/Desktop/arm-mcve/cmain.c:5
$ arm-none-eabi-nm build/output.elf --line-numbers
00008008 T add_numbers
00008038 T cmain
00008000 T _start
Why is there no line number information in the ELF, and how can I add it so that GDB can step through it?
Your linker script discards the sections with debugging information. Look at the default linker script arm-none-eabi-ld --verbose for some ideas. You will at least need some of the DWARF 2 sections:
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
(Adding all of them should work.)

LD giving strange error and not finding an existing file when using ARM gcc

This is the command line executed by my Makefile:
arm-none-eabi-gcc bubblesort.c -O0 -mcpu=cortex-m0 -mthumb -Wl, -T ../boot_and_link/linker.ld -l ../boot_and_link/startup.o
As I understand it, it should compile bubblesort.c for a CortexM0 and then the linker should you use linker.ld as a linker script and should also link startup.o with the output of compiling bubblesort.c.
I get two errors:
/usr/lib/gcc/arm-none-eabi/4.8/../../../arm-none-eabi/bin/ld: cannot find : No such file or directory
/usr/lib/gcc/arm-none-eabi/4.8/../../../arm-none-eabi/bin/ld: cannot find -l../boot_and_link/startup.o
The first one I don't understand. ld tells me it cannot find : which makes no sense and makes me think there an error in my linker script.
The second error is just weird because my linker file is in the exact same location and it finds it and yes I've checked the file's names and they are the same.
Just in case I'm including my linker script on account of it being short and that I wrote it myself (first time) and I'm learning how to write them.
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 8K
ram : ORIGIN = 0x20004000, LENGTH = 16K
stack : ORIGIN = 0x20003FFF, LENGTH = 16K
}
SECTIONS
{
.nvic_vector : { } >rom /*The vector table that is initialized in c code*/
.text :
{
*(.text)
/*_DATAI_BEGIN = .;*/
} >rom
.data :
{
_DATA_LOAD = LOADADDR(.data); /*The absolute address of the data section*/
_DATA_BEGIN = .; /*From where to begin the copy to RAM*/
*(.data)
. = ALIGN(4); /*Make sure the byte boundary is correctly aligned*/
_DATA_END = .; /*Where to end the copy to RAM*/
} >ram AT >rom
.bss :
{
_BSS_BEGIN = .; /* Zero-filled run time allocate data memory */
*(.bss)
_BSS_END = .;
} > ram
.heap :
{
_HEAP = .;
} > ram
.stack :
{
. += LENGTH(stack);
. = ALIGN(4);
_STACKTOP = .; /* The top of the stack is the last available section of memory*/
} >stack
}
Any help would be appreciated.
You could separate compilation and linking, then it's easier to see
flags common both for compiler and linker
flags only for one of these
If you have main.c and startup.c, compilation should look like this:
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -Os -std=gnu99 -o startup.o -c startup.c
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -Os -std=gnu99 -o main.o -c main.c
As for linking
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -nostartfiles -T rom.ld -o main.elf startup.o main.o -lc -lm
If you want it in a single line:
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -Os -std=gnu99 -nostartfiles -T rom.ld -o main.elf startup.c main.c
So the main problem was this line:
arm-none-eabi-gcc bubblesort.c -O0 -mcpu=cortex-m0 -mthumb -Wl, -T ../boot_and_link/linker.ld -l ../boot_and_link/startup.o
This was wrong as the -l switched is used to link with a library and not to just point another object file which was my intention. You need to specify all files for linking as normal ordinary arguments to the linker. The way I ended up doing this was simply (taking Beryllium's advice) separating the compilation and linking into two steps and using two separate calls. Here are the commands that are run by my makefile:
<-------------------- Compiling C Source Files -------------------->
arm-none-eabi-gcc -O0 -c -mcpu=cortex-m0 -mthumb -g bubblesort.c -o bubblesort.o
<-------------------- Linking files -------------------->
arm-none-eabi-ld bubblesort.o ../boot_and_link/startup.o -nostartfiles -T ../boot_and_link/linker.ld -o bubblesort.elf
This worked.
PD: The first error (wher it says it cannot find : No such file or directory) had to to with incorrect spacing in the gcc call. However as I changed it, I cannot exactly recall where it was.

Homemade Kernel linker global variables and inline Strings cannot be accessed

I have followed some tutorials on the web and created my own kernel. It is booting on GRUB with QEMU succesfully. But I have the problem described in this SO question, and I cannot solve it. I can have that workaround described, but I also need to use global variables, it would make the job easier, but I do not understand what should I change in linker to properly use global variables and inline strings.
main.c
struct grub_signature {
unsigned int magic;
unsigned int flags;
unsigned int checksum;
};
#define GRUB_MAGIC 0x1BADB002
#define GRUB_FLAGS 0x0
#define GRUB_CHECKSUM (-1 * (GRUB_MAGIC + GRUB_FLAGS))
struct grub_signature gs __attribute__ ((section (".grub_sig"))) =
{ GRUB_MAGIC, GRUB_FLAGS, GRUB_CHECKSUM };
void putc(unsigned int pos, char c){
char* video = (char*)0xB8000;
video[2 * pos ] = c;
video[2 * pos + 1] = 0x3F;
}
void puts(char* str){
int i = 0;
while(*str){
putc(i++, *(str++));
}
}
void main (void)
{
char txt[] = "MyOS";
puts("where is this text"); // does not work, puts(txt) works.
while(1){};
}
Makefile:
CC = gcc
LD = ld
CFLAGS = -Wall -nostdlib -ffreestanding -m32 -g
LDFLAGS = -T linker.ld -nostdlib -n -melf_i386
SRC = main.c
OBJ = ${SRC:.c=.o}
all: kernel
.c.o:
#echo CC $<
#${CC} -c ${CFLAGS} $<
kernel: ${OBJ} linker.ld
#echo CC -c -o $#
#${LD} ${LDFLAGS} -o kernel ${OBJ}
clean:
#echo cleaning
#rm -f ${OBJ} kernel
.PHONY: all
linker.ld
OUTPUT_FORMAT("elf32-i386")
ENTRY(main)
SECTIONS
{
.grub_sig 0xC0100000 : AT(0x100000)
{
*(.grub_sig)
}
.text :
{
*(.text)
}
.data :
{
*(.data)void main (void)
}
.bss :
{
*(.bss)
}
/DISCARD/ :
{
*(.comment)
*(.eh_frame)
}
}
What works:
void main (void)
{
char txt[] = "MyOS";
puts(txt);
while(1) {}
}
What does not work:
1)
char txt[] = "MyOS";
void main (void)
{
puts(txt);
while(1) {}
}
2)
void main (void)
{
puts("MyOS");
while(1) {}
}
Output of assembly: (external link, because it is a little long) http://hastebin.com/gidebefuga.pl
If you look at objdump -h output, you'll see that virtual and linear addresses do not match for any of the sections. If you look at objdump -d output, you'll see that the addresses are all in the 0xC0100000 range.
However, you do not provide any addressing information in the multiboot header structure; you only provide the minimum three fields. Instead, the boot loader will pick a good address (1M on x86, i.e. 0x00100000, for both virtual and linear addresses), and load the code there.
One might think that that kind of discrepancy should cause the kernel to not run at all, but it just happens that the code generated by the above main.c does not use the addresses for anything except read-only constants. In particular, GCC generates jumps and calls that use relative addresses (signed offsets relative to the address of the next instruction on x86), so the code still runs.
There are two solutions, first one trivial.
Most bootloaders on x86 load the image at the smallest allowed virtual and linear address, 1M (= 0x00100000 = 1048576). Therefore, if you tell your linker script to use both virtual and linear addresses starting at 0x00100000, i.e.
.grub_sig 0x00100000 : AT(0x100000)
{
*(.grub_sig)
}
your kernel will Just Work. I have verified this fixes the issue you are having, after removing the extra void main(void) from your linker script, of course. To be specific, I constructed an 33 MB virtual disk, containing one ext2 partition, installed grub2 on it (using 1.99-21ubuntu3.10) and the above kernel, and ran the image successfully under qemu-kvm 1.0 (1.0+noroms-0ubuntu14.11).
The second option is to set the bit 16 in the multiboot flags, and supply the five additional words necessary to tell the bootloader where the code expects to be resident. However, 0xC0100000 will not work -- at least grub2 will just freak out and reboot --, whereas something like 0x00200000 does work fine. This is because multiboot is really designed to use virtual == linear addresses, and there may be other stuff already present at the highest addresses (similar to why addresses below 1M is avoided).
Note that the boot loader does not provide you with a stack, so it's a bit of a surprise the code works at all.
I personally recommend you use a simple assembler file to construct the signature, and reserve some stack space. For example, start.asm simplified from here,
BITS 32
EXTERN main
GLOBAL start
SECTION .grub_sig
signature:
MAGIC equ 0x1BADB002
FLAGS equ 0
dd MAGIC, FLAGS, -(MAGIC+FLAGS)
SECTION .text
start:
mov esp, _sys_stack ; End of stack area
call main
jmp $ ; Infinite loop
SECTION .bss
resb 16384 ; reserve 16384 bytes for stack
_sys_stack: ; end of stack
compile using
nasm -f elf start.asm -o start.o
and modify your linker script to use start instead of main as the entry point,
ENTRY(start)
Remove the multiboot stuff from your main.c, then compile and link to kernel using e.g.
gcc -Wall -nostdlib -ffreestanding -fno-stack-protector -O3 -fomit-frame-pointer -m32 -c main.c -o main.o
ld -T linker.ld -nostdlib -n -melf_i386 start.o main.o -o kernel
and you have a good start to work on your own kernel.
Questions? Comments?

Hello world, bare metal Beagleboard

I'm trying to get a 'hello world' type program running on my Beagleboard-xm rev. C, by calling a C puts function from assembly.
So far I've been using this as a reference: http://wiki.osdev.org/ARM_Beagleboard
Here's what I have so far, but there's no output.
hello.c
volatile unsigned int * const UART3DR = (unsigned int *)0x49020000;
void puts(const char *s) {
while(*s != '\0') {
*UART3DR = (unsigned int)(*s);
s++;
}
}
void hello() {
puts("Hello, Beagleboard!\n");
}
boot.asm
.global start
start:
ldr sp, =stack_bottom
bl hello
b .
linker.ld
ENTRY(start)
MEMORY
{
ram : ORIGIN = 0x80200000, LENGTH = 0x10000
}
SECTIONS
{
.hello : { hello.o(.text) } > ram
.text : { *(.text) } > ram
.data : { *(.data) } > ram
.bss : { *(.bss) } > ram
. = . + 0x5000; /* 4kB of stack memory */
stack_bottom = .;
}
Makefile
ARMGNU = arm-linux-gnueabi
AOPS = --warn --fatal-warnings
COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding
boot.bin: boot.asm
$(ARMGNU)-as boot.asm -o boot.o
$(ARMGNU)-gcc-4.6 -c $(COPS) hello.c -o hello.o
$(ARMGNU)-ld -T linker.ld hello.o boot.o -o boot.elf
$(ARMGNU)-objdump -D boot.elf > boot.list
$(ARMGNU)-objcopy boot.elf -O srec boot.srec
$(ARMGNU)-objcopy boot.elf -O binary boot.bin
Using just the asm file like this works.
.equ UART3.BASE, 0x49020000
start:
ldr r0,=UART3.BASE
mov r1,#'c'
Here are some Beagleboard/minicom related info: http://paste.ubuntu.com/829072/
Any pointers? :)
I also tried
void hello() {
*UART3DR = 'c';
}
I'm using minicom and send the file via ymodem, then I try to run it with:
go 0x80200000
Hardware and software control flow in minicom are off.
that should have worked for you. Here is some code I dug up from way back when, did not try it on a beagleboard tonight just made sure it compiled, it had worked at one time...
startup.s:
.code 32
.globl _start
_start:
bl main
hang: b hang
.globl PUT32
PUT32:
str r1,[r0]
bx lr
.globl GET32
GET32:
ldr r0,[r0]
bx lr
hello.c :
extern void PUT32 ( unsigned int, unsigned int );
extern unsigned int GET32 ( unsigned int );
void uart_send ( unsigned char x )
{
while((GET32(0x49020014)&0x20)==0x00) continue;
PUT32(0x49020000,x);
}
void hexstring ( unsigned int d )
{
//unsigned int ra;
unsigned int rb;
unsigned int rc;
rb=32;
while(1)
{
rb-=4;
rc=(d>>rb)&0xF;
if(rc>9) rc+=0x37; else rc+=0x30;
uart_send(rc);
if(rb==0) break;
}
uart_send(0x0D);
uart_send(0x0A);
}
int main ( void )
{
hexstring(0x12345678);
return(0);
}
memmap (linker script):
MEMORY
{
ram : ORIGIN = 0x82000000, LENGTH = 256K
}
SECTIONS
{
ROM : { startup.o } > ram
}
Makefile :
CROSS_COMPILE = arm-none-eabi
AOPS = --warn --fatal-warnings
COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding
all : hello.bin
hello.bin : startup.o hello.o memmap
$(CROSS_COMPILE)-ld startup.o hello.o -T memmap -o hello.elf
$(CROSS_COMPILE)-objdump -D hello.elf > hello.list
$(CROSS_COMPILE)-objcopy hello.elf -O binary hello.bin
startup.o : startup.s
$(CROSS_COMPILE)-as $(AOPS) startup.s -o startup.o
hello.o : hello.c
$(CROSS_COMPILE)-gcc -c $(COPS) hello.c -o hello.o
clean :
rm -f *.o
rm -f *.elf
rm -f *.bin
rm -f *.list
Looks like I just left the stack pointer wherever the bootloader had it. Likewise, as you, assumed the bootloader had initialized the serial port.
I assume you have serial port access working, you see uboot and you are able to type commands in order to download this program (xmodem, or whatever) into the boards ram? If you cant do that then it may be you are not connected to the serial port right. the beagleboards serial port is screwy, might need to make your own cable.
You can't just blindly write a string of characters to a UART - you need to check status on each character - it works in the single character example because the UART is always going to be ready for the first character, but for the second and subsequent characters you need to poll (or better yet use an ISR, but let's walk before we run).
There's some good example code here: http://hardwarefreak.wordpress.com/2011/08/30/some-experience-with-the-beagleboard-xm-part-2/
I've not enough repetation to comment..
But my answere to
Works either way. Now the weird thing is that I can print individual
characters with with uart_send('c') for example, but cannot print
strings print_string(char *str){ while (*str != '\0') uart_send
(*str++); } print_string("Test"); . Any thoughts on this?
is:
You write faster in the output buffer, as UART is able to send..
So you've to check, if the output buffer is empty, before you send a new character.
I've done this in the code on my blog (http://hardwarefreak.wordpress.com/2011/08/30/some-experience-with-the-beagleboard-xm-part-2/)

Resources