How to run HelloWorld on ARM - c++

I need to run HelloWorld on arm.
I launch:
$ arm-none-eabi-g++ -mthumb -mcpu=cortex-m3 -c test.cpp -o test
$ file test
test: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), not stripped
$ qemu-arm test <br>
Error while loading test: Permission denied

qemu-system-arm -machine help
...
lm3s811evb Stellaris LM3S811EVB
...
From either the lm3s811 datasheet or looking at the source for the stellaris backend on qemu arm hardware. Uart0 base address is 0x4000C000, the data (rx and tx) register is offset 0x000. From experience the qemu backends tend not to bother with the tx buffer being busy...
flash.s
.cpu cortex-m0
.thumb
.thumb_func
.global _start
_start:
.word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.thumb_func
reset:
bl notmain
b hang
.thumb_func
hang: b .
.thumb_func
.globl PUT32
PUT32:
str r1,[r0]
bx lr
uart01.c
void PUT32 ( unsigned int, unsigned int );
#define UART0BASE 0x4000C000
int notmain ( void )
{
unsigned int rx;
for(rx=0;rx<7;rx++)
{
PUT32(UART0BASE+0x00,0x30+rx);
}
return(0);
}
flash.ld
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
Yep, the stellaris was the first cortex-m3 in silicon that you could buy and I specified cortex-m0. Basically preventing the thumb2 extensions, or most of them. More portable, can easily change that if you want.
arm-none-eabi-as --warn -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=cortex-m0 -mthumb -c uart01.c -o uart01.o
arm-none-eabi-ld -o uart01.elf -T flash.ld flash.o uart01.o
arm-none-eabi-objdump -D uart01.elf > uart01.list
arm-none-eabi-objcopy uart01.elf uart01.bin -O binary
then
qemu-system-arm -M lm3s811evb -m 16K -nographic -kernel uart01.bin
and the output is
0123456
ctrl-a then press x to exit qemu. or
qemu-system-arm -M lm3s811evb -m 16K -kernel uart01.bin
then ctrl-alt-3 (3 not F3) and the serial console pops up with the serial output. when you close that serial console qemu closes.
I want to remember someone telling me that the qemu cortex-m3 support is not that good.
the normal arm cores should be well tested as they are used to cross compile for all kinds of arm target boards. not sure exactly which cores are well tested, but you could do thumb stuff if you booted like an arm but did the rest in thumb, boot with
.globl _start
_start:
b reset
b hang
b hang
b hang
reset:
mov sp,#0x20000
bl notmain
hang:
b hang
the machine
versatilepb ARM Versatile/PB (ARM926EJ-S)
has its uart at 0x101f1000, so
for(ra=0;;ra++)
{
ra&=7;
PUT32(0x101f1000,0x30+ra);
}
can build your app with
arm-none-eabi-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=arm7tdmi -mthumb -c uart01.c -o uart01.o
change your linker script to be all ram based.
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 32K
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.text*) } > ram
}
and then
qemu-system-arm -M versatilepb -m 128M -nographic -kernel hello.bin
(hmmm, does this load at 0x0000, or 0x8000?, shouldnt be too hard to figure out)
you can get mostly the thumb feel of a cortex-m (an m0 basically not an m3, you can find an armv7-a machine you can probably run thumb2 built code (still boots like an arm not a cortex-m)). for example
realview-pb-a8 ARM RealView Platform Baseboard for Cortex-A8
Can probably use newlib almost as is, need to change the crt0.s or whatever it is called these days to boot like an arm not a cortex-m. The rest can build using armv7m and in theory will work.
And or start with the stellaris and just make your own hw support for whatever your real target is and fix the cortex-m3 core if/when you find problems.

Related

What causes failure to unwind in a DWARF perf call stack?

In backtraces produced by perf record --call-graph dwarf and printed by perf script, I am consistently getting wrong addresses for maybe 5% of call stacks, i.e. unwinding fails. One example is
my_bin 770395 705462.825887: 3560360 cycles:
7f0398b9b7e2 __vsnprintf_internal+0x12 (/usr/lib/x86_64-linux-gnu/libc-2.32.so)
7ffcdb6fbfdf [unknown] ([stack])
my_bin 770395 705462.827040: 3447195 cycles:
7f0398ba1624 __GI__IO_default_xsputn+0x104 (inlined)
7ffcdb6fb7af [unknown] ([stack])
and it was produced from this code (compiled with g++ -O3 -g -fno-omit-frame-pointer my_bin.cpp -o my_bin):
#include <cstdio>
#include <iostream>
int __attribute__ ((noinline)) libc_string(int x) {
char buf[64] = {0};
// Some nonsense workload using libc
int res = 0;
for (int i = 0; i < x; ++i) {
res += snprintf(buf, 64, "%d %d %d Can I bring my friends to tea?", (i%10), (i%3)*10, i+2);
res = res % 128;
}
return res;
}
int main() {
int result = libc_string(20000000);
std::cout << result << "\n";
}
I'm pretty sure that my program should not have executable code in the stack, so these addresses seem wrong. It's not only one program, but most programs that I've profiled which have about 5% wrong call stacks. These call stacks mostly just have two stack frames, with the innermost one sometimes in libraries like Eigen (even though they generally have correct calls stacks) and sometimes in the C++ STL or libc. I've seen the unwinding end up in unknown, [stack], [heap], anon, //anon, libstdc++.so.6.0.28, or <my_bin>.
I've seen this on Ubuntu 18.04, 20.04 and 20.10.
This happens only with DWARF unwinding. How can this be fixed?
Which other types of unwinding did you test?
In examples I disabled kernel ASLR feature with setarch x86_64 -R for more stable addresses and smaller perf.data files.
Usage of perf record option -e cycles:u command may help, as it will not include kernel samples.
I have reproduction of similar dwarf unwind issue for files generated with default perf record event ('-e cycles:u'; libc-2.31 from libc6-prof package was used) for __GI__IO_default_xsputn (inlined) function:
env LD_LIBRARY_PATH=/lib/libc6-prof/x86_64-linux-gnu setarch `uname -m` -R perf record --call-graph dwarf -o perf.data.dwarf.u -e cycles:u ./my_bin
perf script -i perf.data.dwarf.u |less
Incorrect sample:
my_bin 28100 760107.271010: 461418 cycles:u:
7ffff7c74f06 __GI__IO_default_xsputn+0x106 (inlined)
7ffff7c59c6c __vfprintf_internal+0xf4c (/usr/lib/libc6-prof/x86_64-linux-gnu/libc-2.31.so)
Correct sample:
my_bin 28100 760107.257283: 267268 cycles:u:
7ffff7c74eff __GI__IO_default_xsputn+0xff (inlined)
7ffff7c59c6c __vfprintf_internal+0xf4c (/usr/lib/libc6-prof/x86_64-linux-gnu/libc-2.31.so)
7ffff7c6e9f6 __vsnprintf_internal+0xb6 (/usr/lib/libc6-prof/x86_64-linux-gnu/libc-2.31.so)
7ffff7d14a2c ___snprintf_chk+0x9c (inlined)
555555555314 libc_string+0xb4 (/home/user/so/my_bin)
555555555314 libc_string+0xb4 (/home/user/so/my_bin)
555555555111 main+0x11 (/home/user/so/my_bin)
7ffff7c040fa __libc_start_main+0x10a (/usr/lib/libc6-prof/x86_64-linux-gnu/libc-2.31.so)
55555555519d _start+0x2d (/home/user/so/my_bin)
For correct unwind I have many different offsets in __GI__IO_default_xsputn+ (the number after +):
perf script -i perf.data.dwarf.u ||grep vsnprintf_internal -B3 |grep _GI__IO_default_xsputn|cut -d + -f 2|sort | uniq -c
...
208 0x0 (inlined)
45 0x101 (inlined)
2 0x105 (inlined)
91 0x10 (inlined)
294 0x110 (inlined)
2 0x117 (inlined)
2 0x11d (inlined)
326 0x121 (inlined)
But I have no +0x106 address with correct unwind. And all incorrect unwinds have +0x106 address. Let's check with gdb (it is easier after ASLR disabling; +262 is +0x106):
env LD_LIBRARY_PATH=/lib/libc6-prof/x86_64-linux-gnu setarch `uname -m` -R gdb -q ./my_bin
(gdb) start
(gdb) x/i 0x7ffff7c74f06
0x7ffff7c74f06 <__GI__IO_default_xsputn+262>: retq
(gdb) disassemble __GI__IO_default_xsputn
Dump of assembler code for function __GI__IO_default_xsputn:
...
0x00007ffff7c74f05 <+261>: pop %rbp
0x00007ffff7c74f06 <+262>: retq
Unwind issue seems to be connected with inlined(?) functions sampled at retq instruction or after pop %rbp?

Unable to boot a custom kernel in VirtualBox : "could not read from boot medium"

I followed the tutorial series on Write your own operating system in 1 hour to create a basic OS to print just "Hello World" with just 4 files : Makefile, kernel.cpp, loader.s and linker.ld.
I am creating a mykernel.iso file but when I boot it into VirtualBox, I get the error "Could not read from boot medium : System halted". I confirmed that the .iso file is linked with my machine instance. Looks like there is some other problem in the code perhaps.
Here is my Makefile:
#we need to tell the compiler to stop assuming that this will be executed inside an OS
CPPPARAMS = -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore
ASPARAMS = --32
LDPARAMS = -melf_i386
objects = loader.o kernel.o
%.o: %.cpp
g++ $(CPPPARAMS) -o $# -c $<
%.o: %.s
as $(ASPARAMS) -o $# $<
mykernel.bin: linker.ld $(objects)
ld $(LDPARAMS) -T $< -o $# $(objects)
install: mykernel.bin
sudo cp $< /boot/mykernel.bin
mykernel.iso: mykernel.bin
mkdir iso
mkdir iso/boot
mkdir iso/boot/grub
cp $< iso/boot/
echo 'set default=0' > iso/boot/grub/grub.cfg
echo 'set timeout=0' >> iso/boot/grub/grub.cfg
echo '' >> iso/boot/grub/grub.cfg
echo 'menuentry "My Personal OS" {' >> iso/boot/grub/grub.cfg
echo 'multiboot /boot/mykernel.bin' >> iso/boot/grub/grub.cfg
echo 'boot' >> iso/boot/grub/grub.cfg
echo '}' >> iso/boot/grub/grub.cfg
grub-mkrescue --output $# iso
rm -rf iso
clean:
rm -rf iso
rm *.o
rm mykernel.iso
rm mykernel.bin
Here is the kernel.cpp
void printf(char *str)
{
unsigned short *VideoMemory = (unsigned short*)0xb8000;
for(int i=0;str[i] != '\0';i++)
VideoMemory[i] = (VideoMemory[i] & 0xFF00) | str[i];
}
typedef void (*constructor)();
extern "C" constructor start_ctors;
extern "C" constructor end_ctors;
extern "C" void callConstructors()
{
for(constructor * i=&start_ctors;i!=&end_ctors;i++)
(*i)();
}
extern "C" void kernelMain(void * multiboot_structure, unsigned int magic_number)
{
printf("Hello World!");
//we do not want to exit from the kernel
while(1);
}
Here is the loader.s :
.set MAGIC, 0x1badb002
.set FLAGS, (1<<0 | 1<<1)
.set CHECKSUM, -(MAGIC + FLAGS)
.section .multiboot
.long MAGIC
.long FLAGS
.long CHECKSUM
.section .text
.extern kernelMain
.extern callConstructors
.global loader
loader:
mov $kernel_stack, %esp
call callConstructors
push %eax #AX register has the pointer of multiboot structure stored by bootloader
push %ebx #BX register has the magic number
call kernelMain
#double check to not come out of the kernel, creating one more loop
_stop:
cli
hlt
jmp _stop
.section .bss
.space 2*1024*1024 #2MB for stack to grow towards left side
kernel_stack:
Here is the linker.ld :
ENTRY(loader)
OUTPUT_FORMAT(elf32-i386)
OUTPUT_ARCH(i386:i386)
SECTIONS
{
. = 0x100000;
.text :
{
*(.multiboot)
*(.text*)
*(.rodata)
}
.data :
{
start_ctors = .;
KEEP(*(.init_array));
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)));
end_ctors = .;
*(.data)
}
.bss :
{
*(.bss)
}
/DISCARD/ :
{
*(.fini_array*)
*(.comment)
}
}
My development environment is Linux Mint 18.1 64-bit with virtualbox installed. My code almost matches the code of the tutor in the series, still I am not able to boot in the virtual machine.
EDIT
I tried with qemu-system-i386 -kernel mykernel.bin and it works fine with a message Hello World.That means there is some problem with VirtualBox environment and configurations.
I ran into the same problem. Just installing grub-pc-bin and recompiling the kernel made it boot successfully on virtual box.
sudo apt-get install grub-pc-bin
Also, I didn't have to change the BSS segment size.
I have no official source for this answer. It is actually based on experience and other questions I have seen on Stackoverflow and some findings I have made.
It appears if you create large kernel bootstrap stacks in the BSS segment it causes GRUB to crash in some environments and not others. This often happens when the total size of the BSS segment seems to reach about 2mb. Virtualbox seems to be a particular case where the issue seems to arise. Issues in Virtualbox seems to vary depending on the version and the virtual hardware configuration being used.
The stack you create in your loader.s to bootstrap your C++ environment doesn't need to be all that big. Once you get your memory management and allocators in place you can reserve area for a larger kernel stack and set SS:ESP to it at that time.
To that end you should consider changing:
.section .bss
.space 2*1024*1024 #2MB for stack to grow towards left side
kernel_stack:
To something 1mb or smaller. I'd probably go with something like 64kb:
.section .bss
.space 64*1024 #64KB for stack to grow towards left side
kernel_stack:

Debugging code through KGDB

I want to debug my code which has some kernel module also. I am able to set breakpoints in kernel as well as in my code. Performing operation hits breakpoints set in kernel code but doesn't hit the breakpoints in my code.
target machine : Machine on which code is to be debugged
host machine : Machine which is used to debug the code
Steps followed:
on host :
$ gdb vmlinux
(vmlinux copied from target machine )
$ gdb> target remote /dev/ttyS1
$ cont
continuing
on target :
$ insmod mymodule.ko
$ cd /sys/module/mymodule/sections/
$ cat .data
$ cat .rodata
$ cat .bss
$ cat .text
$ echo "g" > /proc/sysrq-trigger
on host :
$ add-symbol-file <module_name> <address> \
-s .bss <address> \
-s .rodata <address> \
-s .data <address>
$ b file_name //set break points
$ c
continuing
on target:
execute the command(program) .....but it does not hit the breakpoints......finishes the execution without hitting breakpoints.
But when I tried to set breakpoints to some kernel function like vfs_read(), break-point is being hit.

Error in linking files into a kernel

I have problem. I have compiled file boot.o:
[BITS 16]
[ORG 0x7C00]
[global start]
[extern _main]
start:
call _main
cli
hlt
and compiled C++ file main.o:
int main(){
//processes
}
Im using this LD file linker.ld for linking:
OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS
{
. = 0x100000;
.text ALIGN(4096) :
{
*(.text*)
*(.gnu.linkonce.t*)
}
.rodata ALIGN(4096) :
{
start_ctors = .;
*(.ctor*)
end_ctors = .;
start_dtors = .;
*(.dtor*)
end_dtors = .;
*(.rodata*)
*(.gnu.linkonce.r*)
}
.data ALIGN(4096) :
{
*(.data*)
*(.gnu.linkonce.d*)
}
.bss ALIGN(4096) :
{
*(.COMMON*)
*(.bss*)
*(.gnu.linkonce.b*)
}
}
So I want to start linking and I'm using g++ for windows, and I'm using this commands in cmd: ld -T linker.ld -o kernle.bin main.o boot.o. And is rejecting me error: ld: cannot preform PE operations on non PE output file kernel.bin. Does anybody know how can I repair it? Please help me.
Maybe -oformat bin?
And I doubt you will be able to boot it, anyway... Go read some bootloader tutorials (on osdev.org and brokenthorn.com) and you will get an answer why.
You are using a compiler and toolchain built to make windows executables, not flat binaries. You need a cross compiler for kernel development. Also, you will need a bootloader, a kernel, even minimal, can't fit into the 512 byte bootsector.
Correct me if I'm wrong, but you don't seem to understand the bot process of a pc at all. I suggest reading http://wiki.osdev.org/ as a start.

no debugging symbols found when using gdb

GNU gdb Fedora (6.8-37.el5)
Kernal 2.6.18-164.el5
I am trying to debug my application. However, everytime I pass the binary to the gdb it says:
(no debugging symbols found)
Here is the file output of the binary, and as you can see it is not stripped:
vid: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped
I am compiling with the following CFLAGS:
CFLAGS = -Wall -Wextra -ggdb -O0 -Wunreachable-code
Can anyone tell me if I am missing some simple here?
The most frequent cause of "no debugging symbols found" when -g is present is that there is some "stray" -s or -S argument somewhere on the link line.
From man ld:
-s
--strip-all
Omit all symbol information from the output file.
-S
--strip-debug
Omit debugger symbol information (but not all symbols) from the output file.
The application has to be both compiled and linked with -g option. I.e. you need to put -g in both CPPFLAGS and LDFLAGS.
Some Linux distributions don't use the gdb style debugging symbols. (IIRC they prefer dwarf2.)
In general, gcc and gdb will be in sync as to what kind of debugging symbols they use, and forcing a particular style will just cause problems; unless you know that you need something else, use just -g.
You should also try -ggdb instead of -g if you're compiling for Android!
Replace -ggdb with -g and make sure you aren't stripping the binary with the strip command.
I know this was answered a long time ago, but I've recently spent hours trying to solve a similar problem. The setup is local PC running Debian 8 using Eclipse CDT Neon.2, remote ARM7 board (Olimex) running Debian 7. Tool chain is Linaro 4.9 using gdbserver on the remote board and the Linaro GDB on the local PC. My issue was that the debug session would start and the program would execute, but breakpoints did not work and when manually paused "no source could be found" would result. My compile line options (Linaro gcc) included -ggdb -O0 as many have suggested but still the same problem. Ultimately I tried gdb proper on the remote board and it complained of no symbols. The curious thing was that 'file' reported debug not stripped on the target executable.
I ultimately solved the problem by adding -g to the linker options. I won't claim to fully understand why this helped, but I wanted to pass this on for others just in case it helps. In this case Linux did indeed need -g on the linker options.
Hope the sytem you compiled on and the system you are debugging on have the same architecture. I ran into an issue where debugging symbols of 32 bit binary refused to load up on my 64 bit machine. Switching to a 32 bit system worked for me.
Bazel can strip binaries by default without warning, if that's your build manager. I had to add --strip=never to my bazel build command to get gdb to work, --compilation_mode=dbg may also work.
$ bazel build -s :mithral_wrapped
...
#even with -s option, no '-s' was printed in gcc command
...
$ file bazel-bin/mithral_wrapped.so
../cpp/bazel-bin/mithral_wrapped.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=4528622fb089b579627507876ff14991179a1138, not stripped
$ objdump -h bazel-bin/mithral_wrapped.so | grep debug
$ bazel build -s :mithral_wrapped --strip=never
...
$ file bazel-bin/mithral_wrapped.so
bazel-bin/mithral_wrapped.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=28bd192b145477c2a7d9b058f1e722a29e92a545, not stripped
$ objdump -h bazel-bin/mithral_wrapped.so | grep debug
30 .debug_info 002c8e0e 0000000000000000 0000000000000000 0006b11e 2**0
31 .debug_abbrev 000030f6 0000000000000000 0000000000000000 00333f2c 2**0
32 .debug_loc 0013cfc3 0000000000000000 0000000000000000 00337022 2**0
33 .debug_aranges 00002950 0000000000000000 0000000000000000 00473fe5 2**0
34 .debug_ranges 00011c80 0000000000000000 0000000000000000 00476935 2**0
35 .debug_line 0001e523 0000000000000000 0000000000000000 004885b5 2**0
36 .debug_str 0033dd10 0000000000000000 0000000000000000 004a6ad8 2**0
For those that came here with this question and who are using Qt: in the release config there is a step where the binary is stripped as part of doing the make install. You can pass the configuration option CONFIG+=nostrip to tell it not to:
Instead of:
qmake <your options here, e.g. CONFIG=whatever>
you add CONFIG+=nostrip, so:
qmake <your options here, e.g. CONFIG=whatever> CONFIG+=nostrip
The solutions I've seen so far are good:
must compile with the -g debugging flag to tell the compiler to generate debugging symbols
make sure there is no stray -s in the compiler flags, which strips the output of all symbols.
Just adding on here, since the solution that worked for me wasn't listed anywhere. The order of the compiler flags matters. I was including multiple header files from many locations (-I/usr/local/include -Iutil -I. And I was compiling with all warnings on (-Wall).
The correct recipe for me was:
gcc -I/usr/local/include -Iutil -I -Wall -g -c main.c -o main.o
Notice:
include flags are at the beginning
-Wall is after include flags and before -g
-g is at the end
Any other ordering of the flags would cause no debug symbols to be generated.
I'm using gcc version 11.3.0 on Ubuntu 22.04 on WSL2.