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.
Related
The details of warnings, binary file and system arch are as followed. The c program contains a main and a simple addation function. No external files to be included.
zfq#inginging:~/study/sandbox$ mips64-linux-gnuabi64-gcc sandbox.c
zfq#inginging:~/study/sandbox$ ls
a.out sandbox.c sandbox.h sandbox.s
zfq#inginging:~/study/sandbox$ file a.out
a.out: ELF 64-bit MSB executable, MIPS, MIPS64 rel2 version 1 (SYSV), dynamically linked, interpreter /lib64/ld.so.1, BuildID[sha1]=a16c9c7aba78aa5adcf89b053bdd3c58a7cbe330, for GNU/Linux 3.2.0, not stripped
zfq#inginging:~/study/sandbox$ cat /proc/version
Linux version 5.4.0-65-generic (buildd#lgw01-amd64-048) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #73~18.04.1-Ubuntu SMP Tue Jan 19 09:02:24 UTC 2021
zfq#inginging:~/study/sandbox$ ./a.out
bash: ./a.out: cannot execute binary file: Exec format error
The binary files still have format error even the system is x86_64 architecture and the elf file is also 64bit. Has anyone ever encountered with such a problem?
If you cross-compile, you are telling: Take this source code and translate it to machine-readable format not for this computer but for some other computer/architecture/system.
Therefore a file translated for MIPS can't run on amd64 as these are quite different architecures with completely different instructions.
Try to run in at appropriate architecture - in your case a MIPS64 GNU/Linux computer
Or simly use a native gcc or other cc to produce a binary for the system you are using to compile.
Gbdk works fine on windows but it doesn't work if I try it on linux:
When I run
/usr/lib/gbdk/bin/lcc -Wa-1 -Wl-m -Wl-j -DUSE_SFR_FOR_REG -c main.c -o main.o
it returns this error:
/usr/lib/gbdk/bin/lcc: fatal error in /usr/lib/gbdk/bin/sdcc
That's it. Can anyone please help?
Running cat /etc/os-release returns:
NAME="Linux Mint"
VERSION="19.3 (Tricia)"
ID=linuxmint
ID_LIKE=ubuntu
PRETTY_NAME="Linux Mint 19.3"
VERSION_ID="19.3"
HOME_URL="https://www.linuxmint.com/"
SUPPORT_URL="https://forums.ubuntu.com/"
BUG_REPORT_URL="http://linuxmint-troubleshooting-guide.readthedocs.io/en/latest/"
PRIVACY_POLICY_URL="https://www.linuxmint.com/"
VERSION_CODENAME=tricia
UBUNTU_CODENAME=bionic
Running uname -r returns
5.3.0-46-generic
Running file /usr/lib/gbdk/bin/sdcc returns
/usr/lib/gbdk/bin/sdcc: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 2.0.0, stripped
Running file /usr/lib/gbdk/bin/lcc returns
/usr/lib/gbdk/bin/lcc: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 2.0.0, stripped
Please use https://github.com/gbdk-2020/gbdk-2020 if you were using 20 years old GBDK.
To see the actual error message run sdcc manually, you can feed lcc -v to see which programs it calls with which arguments.
Last time I've seen something like /usr/lib/gbdk/bin/lcc: fatal error in /usr/lib/gbdk/bin/sdcc, it was a segmentation fault. lcc sadly catches errors and replaces them with an unhelpful error message.
I am new in ARM architecture.
I want to compile a simple c code (hello world) and move the output executor onto odroid xu4. (Ubuntu mate 18.04)
But when I move it to odroid. I got this:
bash: ./hello: No such file or directory
I download a toolchain gcc-arm-8.3-2019.03-x86_64-arm-eabi.tar.xz from (https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads) and install on my x86_64 computer(Ubuntu 16.04).
here is my hello_world.c
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
I compile with this cmd:
$ arm-linux-gnueabi-gcc hello_world.c -o hello
Here is the result of file hello
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 3.2.0, BuildID[sha1]=f80d3d5cecbb2d688b978a6c889613f158dda657, not stripped
here is the normal executor build on odroid-xu4 by its native compiler
hello: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib, for GNU/Linux 3.2.0, BuildID[sha1]=697300990ba7610219175192f540cdd7411caa84, not stripped
Thank you!
I'm running Linux Mint 14 with qemu, qemu-user, and the gnueabi toolchain installed. I compiled test.c with arm-linux-gnueabi-gcc test.c -o test.
When I try and run qemu-arm /usr/arm-linux-gnueabi/lib/ld-linux.so.3 test
I get an error saying: test: error while loading shared libraries: test: cannot open shared object file: No such file or directory. Running qemu-arm test, as I've previously tried, gives /lib/ld-linux.so.3: No such file or directory
However, the file does exist and is reachable.
$ stat /usr/arm-linux-gnueabi/lib/ld-linux.so.3
File: `/usr/arm-linux-gnueabi/lib/ld-linux.so.3' -> `ld-2.15.so'
Size: 10 Blocks: 0 IO Block: 4096 symbolic link
Device: 801h/2049d Inode: 4083308 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2013-04-22 16:19:48.090613901 -0700
Modify: 2012-09-21 08:31:29.000000000 -0700
Change: 2013-04-22 15:58:41.042542851 -0700
Birth: -
Does anyone know how I can make qemu run an arm program without having to emulate an entire arm Linux kernel?
test.c is
#include <stdio.h>
int main() {
printf("this had better work\n");
}
and file test is
test: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.31, BuildID[sha1]=0xf2e49db65394b77c77ee5b65b83c0cc9220cbfc0, not stripped
you can run the example by providing a path to the arm-linux-gnueabi shared libs using the -L flag.
qemu-arm -L /usr/arm-linux-gnueabi/
also make sure the LD_LIBRARY_PATH is not set.
unset LD_LIBRARY_PATH
$ export QEMU_LD_PREFIX=/usr/arm-linux-gnueabi
This works for me.
It's basically the same thing as:
$ qemu-arm -L /usr/arm-linux-gnueabi/
You can add it to the ~/.bashrc file so you don't have to type it everytime you open the terminal.
I also met this problem when running a C program with assembly code. My solution is to build the executable with the option "-static", for instance
arm-linux-gnueabi-gcc -static -g main.c square.s
Then
qemu-arm a.out
will not report the error saying "can not find the /lib/ld-linux.so.3".
The only drawback is that the executable could be with a large size. But it's helpful when you just want to test your code.
Of course, you can go with the method from Balau(see artless noise's answer). But if you don't want to feel frustrated by something like "UART serial ports" in this step, which is only to run a simple "test" function, go for a try of my fix.
I solved the problem by copying the following libraries into /lib but I believe there should be a way better solution rather than this nasty solution I invented!
sudo cp /usr/arm-linux-gnueabi/lib/ld-linux.so.3 /lib
sudo cp /usr/arm-linux-gnueabi/lib/libgcc_s.so.1 /lib
sudo cp /usr/arm-linux-gnueabi/lib/libc.so.6 /lib
Please let me know if there are other better solutions as I am interested to know.
If you want to run ARM without Linux, then you need a different compiler (at least). arm-linux-gnueabi-gcc is a compiler for Linux. The compiler and libc are intimately linked. You will need a newlib compiler with a portability layer for qemu.porting newlib
See: Balau and Google newlib+qemu. A newlib port is hosted at Github and seems to the same as the Balau blog.
Typically a non-Linux gcc is called arm-none-eabi-gcc. The prefix arm-none-eabi- is recognized by some configure scripts.
A variant, which worked for me, was to pass the loader library directly and to specify the required library paths using the loader parameter --library-path. For example:
$ TOOLCHAIN_ROOT=/usr/local/gcc-linaro-arm-linux-gnueabihf-4.7-2013.03-20130313_linux/arm-linux-gnueabihf
$ qemu-arm $TOOLCHAIN_ROOT/libc/lib/ld-linux-armhf.so.3 --library-path $TOOLCHAIN_ROOT/libc/lib/arm-linux-gnueabihf:/$TOOLCHAIN_ROOT/lib ./my_executable
Or equivalently export LD_LIBRARY_PATH instead of using --library-path.
i am trying to gdb trietool to understand trietool source code.But it always failed to gdb.
step as below:
(1)./configure CFLAGS=-g
(2)make
and then cd /mnt/hgfs/code/libdatrie-0.2.5/tools,ls -lrt
and gdb trietool-0.2,it will report error as below
/mnt/hgfs/code/libdatrie-0.2.5/tools/trietool-0.2": not in executable format:
and gdb trietool-0.2.o,it is ok,and then type command b ../datrie/trie.c:289,it report
(gdb) b ../datrie/trie.c:289
No source file named ../datrie/trie.c.
But in fact there is trie.c file in datrie dir.
How to fix this issue to get gdb work?Do i miss sth?
Why gdb trietool-0.2 is not ok?
milan#milan:/mnt/hgfs/code/libdatrie-0.2.5/tools$ file trietool-0.2
trietool-0.2: Bourne-Again shell script text executable
/mnt/hgfs/code/libdatrie-0.2.5/tools$ file trietool.o
trietool.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped