-bash: ./ex1: cannot execute binary file: Exec format error [duplicate] - linux

When I try to execute a 32-bit file compiled with gcc -m32 main.c -o main on Windows Subsystem for Linux, I get the following error: bash: ./main: cannot execute binary file: Exec format error.
If I compile it without -m32 it runs.
Any solution for running 32-bit executable on WSL?

QEMU and binfmt support light the way :)
https://github.com/microsoft/wsl/issues/2468#issuecomment-374904520
After reading that the WSLInterop between WSL and Windows processes used binfmt, I was tinkering with QEMU to try some ARM development, and incidentally discovered how to get 32-bit support working.
Edit: requires "Fall Creators Update", 1709, build 16299 or newer
Install qemu and binfmt config:
sudo apt install qemu-user-static
sudo update-binfmts --install i386 /usr/bin/qemu-i386-static --magic '\x7fELF\x01\x01\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x03\x00\x01\x00\x00\x00' --mask '\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xf8\xff\xff\xff\xff\xff\xff\xff'
You'll need to reactivate binfmt support every time you start WSL:
sudo service binfmt-support start
Enable i386 architecture packages:
sudo dpkg --add-architecture i386
sudo apt update
sudo apt install gcc:i386
Try it out:
$ file /usr/bin/gcc-5
/usr/bin/gcc-5: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=2637bb7cb85f8f12b40f03cd015d404930c3c790, stripped
$ /usr/bin/gcc-5 --version
gcc-5 (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gcc helloworld.c -o helloworld
$ ./helloworld
Hello, world!
$ file helloworld
helloworld: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=3a0c7be5c6a8d45613e4ef2b7b3474df6224a5da, not stripped
And to prove it really was working, disable i386 support and try again:
$ sudo service binfmt-support stop
* Disabling additional executable binary formats binfmt-support [ OK ]
$ ./helloworld
-bash: ./helloworld: cannot execute binary file: Exec format error

32-bit ELF support isn't provided by WSL (yet). There doesn't seem to be any progress since the UserVoice was raised - you are out luck.
See UserVoice: Please add 32 bit ELF support to the kernel and Support for 32-bit i386 ELF binaries.
If possible, switch to a real Linux ;-)
Since this was originally posted, the support has been available on WSL2 which does support real Linux kernel! So that should be the preferred way.
As noted in the linked github issue, there's also qemu-user which can be used if WSL1 is still used.

WSL2 runs in a real virtual machine using a real Linux kernel, therefore it's actually possible to do anything a Linux VM can do, including running 32-bit code. Just install 32-bit libs by running
sudo dpkg --add-architecture i386
sudo apt-get update
For more information read
Announcing WSL 2
WSL 2 FAQ

Related

Hello world cross compiled for ARM is runing on both x86_64 and ARM

I was preparing a demonstration of user mode Qemu's (qemu-user package) qemu-arm. To do so, I used a simple hello world C program hello.c:
#include <stdio.h>
int main()
{
printf("Oi, Qemu!\nPrograma C aqui!\n");
}
To cross compile it (statically linked), I used the cross toolchain from gcc-arm-linux-gnueabihf:
$ arm-linux-gnueabihf-gcc --version
arm-linux-gnueabihf-gcc (Ubuntu 9.3.0-10ubuntu1) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ arm-linux-gnueabihf-gcc hello.c -o hello_c_static -static
The output runs in both qemu-arm, Beaglebone Black AND ON THE PC.
How is it possible?!
EDIT
About the compiled executable:
file hello_c_static
hello_c_static: ELF 32-bit LSB executable, ARM, EABI5 version 1
(GNU/Linux), statically linked,
BuildID[sha1]=6a33aaa5abb9a14fbc0ca4f2e7b432d6fa5d7067, for GNU/Linux 3.2.0,
not stripped
Check ls -l /proc/sys/fs/binfmt_misc/ to see if your x86 system is set up to transparently run qemu on ARM binaries for you, the same way it can be to run WIINE on Windows executables or whatever using Linux binfmt_misc. https://en.wikipedia.org/wiki/Binfmt_misc
Admin guide https://www.kernel.org/doc/Documentation/admin-guide/binfmt-misc.rst
The installer for the qemu-user package might have registered the executable formats it supports.
With no binfmts registers, you'll just have the register and status "files". On my system, WINE and Mono boot scripts have registered handlers so I also see CLR and DOSWin files. e.g.
$ cat /proc/sys/fs/binfmt_misc/DOSWin
enabled
interpreter /usr/bin/wine
flags:
offset 0
magic 4d5a
If there's somehow a different mechanism, try using strace ./some_arm_program to see what system calls happen when you execute it.
Maybe also suspend it while it's running (control-z) and look at /proc/$(pidof some_arm_program)/maps and other files.
(This last section was written after the OP commented that they only saw register and status files, not qemu-arm, but they've since change their comment. It looks like binfmt-support is the answer.)

Specify the expected Linux version of the output binary of GCC

I'm helping others doing a lab experiment of the "operating systems concepts" course. The experiment task is to compile Linux 2.6.26 and run it in QEMU.
After compiling the Linux kernel, we're told to write a smallest program to serve as the init program. The example we're presented (and we followed) is:
#include <stdio.h>
int main() {
while (1) {
puts("Hello!");
sleep(2);
}
}
The compilation command is:
root#ubuntu:/home/vmware/oslab# gcc --version
gcc (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
root#ubuntu:/home/vmware/oslab# gcc -static -o init hello.c
The host environment should be a freshly-installed Ubuntu 14.04.6 (i386).
The problem is, one of my fellow students followed the instruction carefully, and the init program failed to execute. I asked him for his whole initrd.img, and noticed how his init program looks different:
vmware#ubuntu:~/oslab$ file mnt/init
mnt/init: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=7365ac494ef1d924c171899c169dbd3195d2d209, not stripped
To me, that's clearly not something that can run on Linux 2.6.26. With GCC 4.8 provided in the Ubuntu APT repository (trusty), how can I get GCC to output something that runs on Linux 2.6.26?
FYI: On my own testing VM (also Ubuntu 14.04.6, Linux 4.4, same latest GCC version from Ubuntu APT repo as of April 2, 2019), the compiled program shows Linux 2.6.24 in file output. Also, his binary runs perfectly well in QEMU with my freshly compiled 2.6.32.37 kernel.
Specify the expected Linux version of the output binary of GCC
in your question you speak about the version of libc C but that can also concerns a lot of other libs, and may be you want also produce 32b and/or 64b executable(s).
For me the most secure way is to use pbuilder, I use it to produce BoUML debs for Ubuntu Cosmic (18.10) Bionic (18.04), Artful (17.10) Zesty (17.04) Yakkety (16.10) Xenial (16.04) Trusty (14.04) and Precise (12.04) and that in both 32b and 64b, and I do all of that from my Ubuntu Xenial 64b just doing the appropriate sequence of pbuilder commands (without any reboot to go in each Linux release)
That needs time to generate a version but because this is made in the corresponding Linux version you are sure of the result.
The provided lab environment was Ubuntu 14.04, where the package libc6 has version 2.19-0ubuntu6.14.
The lab instruction provided by the teaching assistants contained an instruction to change the APT source by editing /etc/apt/sources.list manually, which had a SERIOUS disaster in it: The "version" string in the edited example was xenial instead of trusty, which, if followed, would factually update your system to Xenial (Ubuntu 16.04). The new version of libc6 was 2.23-0ubuntu11, which would cause as and ld (from binutils, not related to GCC) to output ELF with a minimum Linux version of 2.6.32.
With glibc version 2.19, the output ELF is compatible with Linux 2.6.24, but with glibc 2.23, the output is only compatible with Linux 2.6.32.
I tested and verified this by compiling a test program under Ubuntu 14.04 and checking the ELF information, then replaced all trusty with xenial, did apt-get update and only updated binutils and its dependencies (which includes libc6), and compiled the program and checked it again.

Finding gcc location

I am on a cluster and do not have root permission, I am new to linux. I wish to run a tool with a gcc 5 version or less. My default gcc version is 6.3.0. But there is another version of gcc (gcc 4:6.3.0-4) on the system. I am trying to find its location so that I can set CC and CXX variable value to that location (e.g. export CC="/usr/bin/gcc"). I tried which gcc (it is pointing to my default gcc location) and whereis gcc. I am not able to find the location of other gcc. It would be really helpful if someone can share the way to do it.
dpkg --list | grep compiler
Name Version Architecture Description
gcc 4:6.3.0-4 amd64 GNU C compiler
gcc-6 6.3.0-18+deb9u1 amd64 GNU C compiler
My system description is as follows:
Linux b03 4.9.0-6-amd64 #1 SMP Debian 4.9.82-1+deb9u3 (2018-03-02) x86_64 GNU/Linux
Running dpkg -L gcc 4:6.3.0-4 will give you a list of all files installed by that package. You should be able to find the executable path in there.

Build binary (telnet) for 2.4.0 kernel, i586 architecture

I am trying to cross-compile a binary to use on an old Linux distribution (kernel 2.4.25, i586 architecture).
Steps I took
I have downloaded the landley i586 cross-compiler (http://landley.net/aboriginal/downloads/binaries/)
I downloaded the net-utils source: https://ftp.gnu.org/gnu/inetutils/ version 1.9.4
I included the cross-compiler in my path: export PATH=/root/Documents/cross-compiler-i586/bin/:$PATH
I then built the telnet binary as follows: LDFLAGS=”-static" ./configure --host=i586 --build=x86_64 --target=i586 --disable-ifconfig --with-ncurses-include-dir=/root/Documents/tnbuild --disable-hostname --disable-logger --disable-rcp --disable-rexec --disable-rlogin --disable-rsh --disable-tftp --disable-traceroute --disable-inetd --disable-rexecd --disable-syslogd --disable-tftpd
This successfully compiled, and checking (after stripping) the binary with the file command gives: telnet: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, stripped
I compared this with a binary which is already on the old Linux system, and the output is exactly the same: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter lib/ld-linux.so.2, for GNU/Linux 2.4.0, stripped
The problem I am facing
The telnet binary that I compiled is not working on the old Linux system. The error that is thrown is simply 'Segmentation Fault'. Googling this error learns that it is likely due to differences in architecture (i586?), but I have no clue anymore how to fix it, as the 'file' command outputs exactly the same for a working binary as well as for the failing binary.
I then stumbled across this topic: GCC Cross compile to a i586 architecture (Vortex86DX) , but as it is not pursued, I am not sure if I should indeed compile all toolchains for i586 and how exactly I would need to do that.
Is there a specific reason you want to cross-compile this rather than just compiling for generic 32-bit i386? You may need to disable some compiler optimizations if they are not supported by the CPU, but you probably don't need to create a staticly-linked binary.
These instructions for compiling 32-bit (-m 32) seem sufficient to create the telnet binary.
They boil down to:
apt-get install gcc-multilib;
./configure CFLAGS='-m32' -disable-ifconfig \
--with-ncurses-include-dir=/root/Documents/tnbuild \
--disable-hostname --disable-logger --disable-rcp \
--disable-rexec --disable-rlogin --disable-rsh \
--disable-tftp --disable-traceroute --disable-inetd \
--disable-rexecd --disable-syslogd --disable-tftpd
make

Running valgrind 32bit binaries on 64 bit machine

I'm trying to run valgrind 32bit binaries on 64 bit machine(linux) and i'm getting this error:
valgrind: failed to start tool 'memcheck' for platform 'x86-linux': No
such file or directory
What do i need to do to make it work?
You do not have installed Valgrind for analysing 32-bit programs on your Linux distribution.
For example on Ubuntu 15.04, installing Valgrind via
apt-get install valgrind
installs both 32-bit and 64-bit versions of the Valgrind analytical tools:
$ ls -1 /usr/lib/valgrind/memcheck-*
/usr/lib/valgrind/memcheck-amd64-linux
/usr/lib/valgrind/memcheck-x86-linux
What is you Linux distribution?
I had the same issue and fixed it by setting VALGRIND_LIB to Valgrind's library path (eg. /usr/local/lib/valgrind) in my .bashrc:
export VALGRIND_LIB="/usr/local/lib/valgrind"
I don't know why this is not mentioned in the Valgrind Installation Instructions or why I had to add this following these instructions, however I found this hint in the README_DEVELOPERS shipped with the sources.

Resources