this is my code and I want to run it on a cortex-m4 linux based board (stm32f429) but before that I want to test my program on my pc using qemu.
#include <iostream>
int main()
{
std::cout << "Hello, World!" << std::endl;
return 0;
}
I have compiled it with this command : arm-linux-gnueabi-g++ -static -mcpu=cortex-m4 hello.cpp -o hello and I checked the generated elf file with readelf and this is the output:
$ readelf -A hello
Attribute Section: aeabi
File Attributes
Tag_CPU_name: "7E-M"
Tag_CPU_arch: v7E-M
Tag_CPU_arch_profile: Microcontroller
Tag_ARM_ISA_use: Yes
Tag_THUMB_ISA_use: Thumb-2
Tag_ABI_PCS_wchar_t: 4
Tag_ABI_FP_rounding: Needed
Tag_ABI_FP_denormal: Needed
Tag_ABI_FP_exceptions: Needed
Tag_ABI_FP_number_model: IEEE 754
Tag_ABI_align_needed: 8-byte
Tag_ABI_align_preserved: 8-byte, except leaf SP
Tag_ABI_enum_size: int
Tag_CPU_unaligned_access: v6
this is how I'm trying to emulate it: qemu-arm -cpu cortex-m4 hello
but it throws this error:
qemu: uncaught target signal 4 (Illegal instruction) - core dumped
Illegal instruction
even when I tryied to run it on my physical board, my kernel throwed error -8 which is a ENOEXEC error or basicaly: Exec format error
I tryed it with all cortex-m CPUs but none of them worked (cortex m0, m3, m4, m7)
what is wrong with my elf file? why qemu and my physical board throws this error?
Related
I am running a Kali Linux distribution on an arm cpu (aarch64).
I have successfully install x86_64-linux-gnux32-gcc and x86_64-linux-gnu-gcc.
I have wrote a basic c program:
#include <stdio.h>
void main()
{
printf("Hello world\n");
}
I have compiled 2 versions:
x86_64-linux-gnu-gcc test1.c -o test1_64
x86_64-linux-gnux32-gcc test1.c -o test1_32
The first binary (64 bits) works fine when i run it with this command:
qemu-x86_64-static ./test1_64
But i have an error with the second binary (32 bits):
qemu-x86_64-static ./test1_32
qemu-x86_64-static: ./test1_32: Invalid ELF image for this architecture
I have tried to force a 32 bits cpu with this command:
qemu-x86_64-static -cpu qemu32 ./test1_32
I have also tried to compile the binary with -static option. I got the same result.
How can i run my 32 bits executable ?
Thanks a lot
x86_64-linux-gnux32-gcc is not what you want for building 32-bit programs. This is actually a 64-bit compiler that targets the x32 ABI, a scheme to have 64-bit code that needs only 32 bits for pointers. It never really caught on and is fairly obscure these days, so I'm not surprised that qemu wouldn't support it.
The x86_64 target of gcc supports building 32-bit programs as well, using the -m32 option. So you ought to be able to build your 32-bit Hello World with
x86_64-linux-gnu-gcc test1.c -o test1_32 -m32
(You might have to separately install 32-bit x86 libraries to successfully cross compile.)
Then to run it, use qemu-i386 instead of qemu-x86_64.
file ./test1_32 should show you that you've still made an x86-64 executable, not i386, with a compiler for the x32 ABI as Nate noticed.
Unfortunately the file output says "ELF 32-bit LSB executable, x86-64, version 1 (SYSV), ..." so the 32-bit part could be misleading.
An actual 32-bit build has "ELF 32-bit LSB executable, Intel 80386,".
A single install of GCC/GAS can build for 32 or 64-bit x86, unlike for ARM32 vs. AArch64 where you need different builds of GCC, so I expect that was part of the confusion. GCC treats i386 and x86-64 as flavours of the same architecture, while AArch64 is treated as a totally separate architecture from ARM. (IDK if GCC did that because x86-64 machine code is similar to 32-bit, so the same assembler can pretty easily handle both. But AArch64 uses a totally different machine code format from ARM32, no point in trying to share code in the assembler between the two architectures.)
So you were probably expecting to need a GCC with 32 in its name to make 32-bit x86 executables. That is not the case.
Currently, I'm trying to test an arm assembly code that I wrote. I work on Ubuntu, so I downloaded a cross compiler tool chain (arm-linux-gnueabi) so I can compile my code and then I test it using qemu-arm. But when I try to compile with arm-none-eabi-gcc it compiles but it doesn't work with qemu-arm. My guess is it doesn't work because I'm compiling for bare metal arm environment. My question is how can I use qemu-system-arm instead of qemu-arm to simulate a bare metal arm environment and test my code ?
You want assembly you only need binutils, dont use a C compiler on assembly, it may work but doesnt that just leave a bad taste in your mouth? You probably didnt separately link and/or left the stock bootstrap and linker script with arm-non-eabi-gcc. The example below does not care about arm-none-eabi- vs arm-linux-gnueabi-
Qemu uarts tend to not actually implement an amount of time to wait for the character to go out, nor need any initialization, YMMV.
memmap
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 32K
}
SECTIONS
{
.text : { *(.text*) } > ram
}
so.s
.globl _start
_start:
b reset
b hang
b hang
b hang
b hang
b hang
b hang
b hang
hang: b hang
reset:
ldr r0,=0x101f1000
mov r1,#0
top:
add r1,r1,#1
and r1,r1,#0x07
orr r1,r1,#0x30
str r1,[r0]
b top
build
arm-linux-gnueabi-as --warn --fatal-warnings -march=armv5t so.s -o so.o
arm-linux-gnueabi-ld so.o -T memmap -o notmain.elf
arm-linux-gnueabi-objdump -D notmain.elf > notmain.list
arm-linux-gnueabi-objcopy notmain.elf -O binary notmain.bin
run
qemu-system-arm -M versatilepb -m 128M -nographic -kernel notmain.bin
then ctrl-a then x to exit the qemu console back to the command line.
This will print out 1234567012345670... forever or until you stop it
Another way to run is
qemu-system-arm -M versatilepb -m 128M -kernel notmain.bin
and then ctrl-alt-3 (not F3 but 3) will switch to the serial0 console
and you can see the output, and can close out of the qemu console when done.
There are other machines you can experiment with. Their peripherals of course will vary, as well as the architecture, most should be either compatible with armv4 arm instructions or thumb instructions if a cortex-m.
Adding C functions to this is fairly simple.
I'm using the Docker container (thewtex/cross-compiler-linux-armv7) to cross-compile a simple "Hello World" Linux user space C program on an x86_64 system. The target system is a ARMv7 embedded system (in particular a Kobo Aura HD e-reader with stock firmware).
The source code of the program (hello_world.c) is as follows
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World!\n");
return 0;
}
Unexpectedly, I can execute the resulting executable on the host system:
andreas#andreas-pc:~/tmp/test$ uname -a && ./hello
Linux andreas-pc 4.5.5-201.fc23.x86_64 #1 SMP Sat May 21 15:29:49 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
Hello World!
as well as on the target device
[root#(none) onboard]# uname -a && ./hello
Linux (none) 2.6.35.3-850-gbc67621+ #1038 PREEMPT Thu Apr 25 15:48:22 CST 2013 armv7l GNU/Linux
Hello World!
Is there any explanation for this?
For reference, I invoke the compiler using the following set of commands
docker run thewtex/cross-compiler-linux-armv7 > ./dockcross.sh
chmod +x dockcross.sh
For some reason the generated shell script is buggy, I manually have to replace /cross-compiler-base/cross-compiler-linux-armv7/ and /:build/:build:z/ in dockcross.sh. Now I run
./dockcross.sh arm-linux-gnueabihf-cc hello_world.c -static -o hello
file returns the following information about the resulting hello executable
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=317a9ea164931f614b24e98dec743050e2d7f900, not stripped
There is a mechanism in the Linux kernel called binfmt_misc that can be used to associate arbitrary interpreters with executables. This association can either be based on a magic byte sequence at the beginning of the executable itself, or its file extension (e.g., wine automatically registers itself for *.exe files). Interpreters are registered in the kernel by writing to the /proc/sys/fs/binfmt_misc/ sysfs.
On Fedora, the systemd-binfmt service is responsible for the interpreter registration. It reads a set of configuration files from the /usr/lib/binfmt.d directory and performs the necessary writes to the sysfs. In the context of the above question, installation of the qemu emulator-suite will place the corresponding configuration files in this directory. For ARM this file is called qemu-arm and has the following content:
enabled
interpreter /usr/bin/qemu-arm
flags:
offset 0
magic 7f454c4601010100000000000000000002002800
mask ffffffffffffff00fffffffffffffffffeffffff
This allows to transparently execute statically linked ARM executables on Linux. Thanks to Mark Plotnick for pointing this mechanism out.
I can use libsodium 1.0.7 just fine in Ubuntu but there seems to be some issue when trying to cross-compile the libsodium library to an armv5 architecture (armv5tejl-unknown-linux-gnueabihf).
I have used ./configure --host=armv5tejl-unknown-linux-gnueabihf and then make DESTDIR=/home/myself/ARM/.
All files are generated fine (headers and static & shared library files) and I can compile and link a small test C-program which then generates a segmentation fault when it's executed on my ARMv5 target (toolchain and all is fine, everything else I compile & link not using libsodium runs perfectly fine on my ARM machine):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sodium.h"
int main()
{
printf("sodium_init()=%d\n",sodium_init()); // Fine, = 0
unsigned char pbk[crypto_box_PUBLICKEYBYTES];
unsigned char sbk[crypto_box_SECRETKEYBYTES];
crypto_box_keypair(pbk,sbk); // <-- Segmentation fault.
}
I have also tried the official cross-compile for ARM instructions at https://download.libsodium.org/doc/installation/index.html but configure fails due to a missing nosys.specs file. Is there somewhere I can download this (I have goggled it and it seems that it has to be specifically generated for the libsodium package)?
I managed to solve it with some help here : github.com/jedisct1/libsodium/issues/331
– Tias
Right, I finally managed to make it run on my ARMv5 target by doing
the following, many thanks for pointing me to the ARM toolchain that
contained the nosys.spec & libnosys.a files :
Downloaded ARM toolchain
gcc-arm-none-eabi-4_9-2015q3-20150921-linux.tar.bz2 from
https://launchpad.net/gcc-arm-embedded
Downloaded libsodium-1.0.7 from https://download.libsodium.org/libsodium/releases/
Note: This is for making a static
libsodium.a Example below assuming home folder =
/home/user tar xvjf gcc-arm-none-eabi-4_9-2015q3-20150921-linux.tar.bz2
tar xvzf libsodium-1.0.7.tar.gz
cp ./gcc-arm-none-eabi-4_9-2015q3/arm-none-eabi/lib/nosys.spec ./libsodium-1.0.7/
cp ./gcc-arm-none-eabi-4_9-2015q3/arm-none-eabi/lib/libnosys.a ./libsodium-1.0.7/ Folder gcc-arm-none-eabi-4_9-can
be deleted at this point. cd ./libsodium-1.0.7/
mkdir ARMv5
export LDFLAGS='-static -g --specs=nosys.specs -L/home/user/libsodium-1.0.7/ -lnosys -lc'
./configure --host=armv5tejl-unknown-linux-gnueabihf --enable-static --prefix=/home/user/libsodium-1.0.7/ARMv5/
make DESTDIR=/home/user/libsodium-1.0.7/ARMv5/ Key
discoveries for me : Hint from jedisct1 where to get the
ARM toolchain containing both the nosys.spec and
libnosys.a files. Found out to add linker flag
-lc to make libsodium with libc (contaning
__libc_start_main, abort,
__libc_csu_fini and __libc_csu_init)
I am a newbie in writing bootloaders. I have written a helloworld bootloader in asm, and
I am now trying to write one in C. I have written a helloworld bootloader in C, but I cannot compile it.
This is my code. What am I doing wrong? Why won't it compile?
void print_char();
int main(void){
char *MSG = "Hello World!";
int i;
__asm__(
"mov %0, %%SI;"
:
:"g"(MSG)
);
for(i=0;i<12;i++){
__asm__(
"mov %0, %%AL;"
:
:"g"(MSG[i])
);
print_char();
}
return 0;
}
void print_char(){
__asm__(
"mov $0X0E, %AH;"
"mov $0x00, %BH;"
"mov $0x04, %BL;"
"int $0x10"
);
}
Let me assume a lot of things here: you want to run your bootloader on an x86 system, you have the gcc toolchain set up on a *nix box.
There are some points to be taken into account when writing a bootloader:
the 510 byte limit for a VBR, even lesser for MBR due to partition table (if your system needs one)
real mode - 16 bit registers and seg:off addressing
bootloader must be flat binary that must be linked to run at physical address 7c00h
no external 'library' references (duh!)
now if you want gcc to output such a binary, you need to play some tricks with it.
gcc by default splits out 32bit code. To have gcc output code that would run in real mode, add __asm__(".code16gcc\n") at the top of each C file.
gcc outputs compiled objects in ELF. We need a bin that is statically linked at 7c00h. Create a file linker.ld with following contents
ENTRY(main);
SECTIONS
{
. = 0x7C00;
.text : AT(0x7C00)
{
_text = .;
*(.text);
_text_end = .;
}
.data :
{
_data = .;
*(.bss);
*(.bss*);
*(.data);
*(.rodata*);
*(COMMON)
_data_end = .;
}
.sig : AT(0x7DFE)
{
SHORT(0xaa55);
}
/DISCARD/ :
{
*(.note*);
*(.iplt*);
*(.igot*);
*(.rel*);
*(.comment);
/* add any unwanted sections spewed out by your version of gcc and flags here */
}
}
write your bootloader code in bootloader.c and build the bootloader
$ gcc -c -g -Os -march=i686 -ffreestanding -Wall -Werror -I. -o bootloader.o bootloader.c
$ ld -static -Tlinker.ld -nostdlib --nmagic -o bootloader.elf bootloader.o
$ objcopy -O binary bootloader.elf bootloader.bin
Since you already have built boot loaders with ASM, I guess the rest is obvious to you.
-
taken from my blog: http://dc0d32.blogspot.in/2010/06/real-mode-in-c-with-gcc-writing.html
A bootloader is written in ASM.
When compiling C code (or C++, or whatever), a compiler will 'transform' your human readable code into machine code. So you can't be sure about the result.
When a PC boots, the BIOS will execute code from a specific address.
That code needs to be executable, directly.
That's why you'll use assembly.
It's the only way to have un-altered code, that will be run as written, by the processor.
If you want to code in C, you'll still have to code an ASM bootloader, which will be in charge to load properly the machine code generated by the compiler you use.
You need to understand that each compiler will generate different machine codes, that may need pre-processing before execution.
The BIOS won't let you pre-process your machine code. The PC boot is just a jump to a memory location, meaning the machine code located at this location will be directly executed.
Since you are using GCC, you should read the info pages about the different "target environments". You most probably want to use the -ffreestanding flag. Also I had to use -fno-stack-protector flags to avoid some ugly magic of the compiler.
Then, you will get linker errors saying that memset and the like are not found. So you should implement your own version of these and link them in.
I tried this a few years ago -- options may have changed.
You have to run gcc with -ffreestanding (don't link) and then link using ld with the flags -static, -nostdlib
As far as I know, you cannot write bootloader in C. That is because, C needs you to work in a 32-bit protected mode while in bootloader some portions are in 16-bit mode.