difference between i386:x64-32 vs i386 vs i386:x86_64 - linux

Can someone explain the difference between the three architectures?
Actually when I built a 64-bit application in Linux, I got a link error saying:
skipping incompatible library.a when searching for library.a
Then I used objdump -f on that library and I got the below output:
a.o: file format elf32-x86-64
architecture: i386:x64-32, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x00000000
Does it mean the library is 32-bit? Is that the reason I am getting the linker error?

There are 3 common ABIs usable on standard Intel-compatible machines (not Itanium).
The classic 32-bit architecture, often called "x86" for short, which has triples like i[3-6]86-linux-gnu. Registers and pointers are both 32 bits.
The 64-bit extension originally from AMD, often called "amd64" for short, which has GNU triple of x86_64-linux-gnu. Registers and pointers are both 64 bits.
The new "x32" ABI, with a triple of x86_64-linux-gnux32. Registers are 64 bits, but pointers are only 32 bits, saving a lot of memory in pointer-heavy workflows. It also ensures all the other 64-bit only processor features are available.
Each of the above has its on system call interface, own ld.so, own complete set of libraries, etc. But it is possible to run all 3 on the same kernel.
On Linux, their loaders are:
% objdump -f /lib/ld-linux.so.2 /lib64/ld-linux-x86-64.so.2 /libx32/ld-linux-x32.so.2
/lib/ld-linux.so.2: file format elf32-i386
architecture: i386, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x00000a90
/lib64/ld-linux-x86-64.so.2: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0000000000000c90
/libx32/ld-linux-x32.so.2: file format elf32-x86-64
architecture: i386:x64-32, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x00000960
Now, if you're getting the message about "skipping incompatible library", that means something is messed up with your configuration. Make sure you don't have bad variables in the environment or passed on the command line, or files installed outside of your package manager's control.

Beyond usual full 64bit and good old 32bit ABI there is a special ABI (inspired by SGI n32 envirnment) where pointers are 32bit (thus they are 32bit apps), but it is designed to run on 64bit host and have full access to all x64 goodies:
native x64 registers and math
more registers
SSE2/3/4, AVX1/2/...
Full 4Gb address space on 64bit host
It is called x32 ABI, link: https://en.wikipedia.org/wiki/X32_ABI
UPDATE
On Ubuntu system I have to install two packages (with deps) to get x32 working:
> sudo apt install gcc-multilib
> sudo apt install libx32stdc++-5-dev
Then compiling simlple C++ code with g++ -mx32 hellow.cpp works, making x32 executable
> file a.out
./a.out: ELF 32-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libx32/ld-linux-x32.so.2, for GNU/Linux 3.4.0

Related

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

Run 32-bit executable directly on 64-bit linux system

After migrating a Debian 7.6 system from i368 to amd64 I encountered the problem to use some older ELF 32-bit LSB executables. Of course, there is the possibility to setup a secondary 32-bit system (in fact I could use my old one) and to apply chroot(8) or schroot(1). But I do not like the additional admin effort, the performance loss by a wrapper program and a different command sequence.
I am wondering whether there is really no way to run a 32-bit application directly on the x86_64 architecture (as possible, e.g., for HP-UX 11.0)? Both
$ /home/alf/prog32
and
$ /usr/bin/linux32 /home/alf/prog32
just lead to the failure message /home/alf/prog32: file or directory not found. This behavior is observed for all ELF 32-bit LSB executables (Debian i386, downloaded, self-written and compiled C-programs).

Loading 64-bit module to a 32-bit kernel using insmod

Is is possible to load a .ko file (kernel object file) which was compiled in 64-bit processor system into 32 bit processor system?
Actually I am getting following error when I issue the insmod command in my system:
insmod: error inserting 'be2net.ko': -1 Invalid module format
It is not possible to run 64-bit code in a 32-bit system. Depending on the requirements, the reverse can be true (running 32-bit software or libraries in a 64-bit system), but a 32-bit architecture cannot understand 64-bit code. You will need to compile the module on your system.
First download the kernel source from kernel.org. Then extract, and cd into
linux/drivers/net/benet
Once there, type (as your regular user)
make
and then
sudo insmod be2net.ko
That should work for you.
No, it is not possible to load 64-bit modules to a 32-bit kernel, and that is why you are getting an error. The reason is that 64 and 32-bit program have an incompatible ABI (e.g. different calling conventions). That is also the reason 64-bit applications can't be linked with 32-bit libraries, for example.
Note that insmod generally gives vague error message. For a more detailed message look at the output of dmesg.
The processor where it was compiled matters not at all. The compiler and compiler options do matter. If it was compiled FOR a 64-bit processor, it cannot run on a 32-bit processor, because it uses a different instruction set.
However, a 64-bit processor can run a cross-compiler and create 32-bit binaries. It is unlikely that you've done this.

How to distinguish between mips cpu types on linux when dpkg-architecture is absent?

Short question: how can I reliably distinguish between mips, mipsel, mips64 and mips64el on any linux distribution?
Longer explanation:
We provide statically built/distribution independent binaries (for TeX) for many architectures. Installation script usually runs uname -s and uname -m to determine operating system and architecture. Binaries are then fetched from server based on that decision, so it needs to works reliably. And it does. Almost everywhere except for Mac OS X 10.6 and Debian. Mac would report i386 on OS that runs 64-bit applications, while Debian reports mips64 for 32-bit OS.
Debian on mips64 correctly reports processor type, but that doesn't help me for at least two reasons:
OS is 32-bit, not 64-bit as the name might suggest.
It is running in little-endian mode. Debian calls that mipsel, not mips. It can often be switched, but OS only runs in one mode and mips software is often incompatible with mipsel.
Here are some outputs from system commands:
$ file my_binary_name
my_binary_name: ELF 32-bit LSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, with unknown capability 0xf41 = 0x756e6700, with unknown capability 0x70100 = 0x1040000, stripped
$ dpkg-architecture
DEB_BUILD_ARCH=mipsel
DEB_BUILD_ARCH_OS=linux
DEB_BUILD_ARCH_CPU=mipsel
DEB_BUILD_ARCH_BITS=32
DEB_BUILD_ARCH_ENDIAN=little
DEB_BUILD_GNU_CPU=mipsel
DEB_BUILD_GNU_SYSTEM=linux-gnu
DEB_BUILD_GNU_TYPE=mipsel-linux-gnu
DEB_HOST_ARCH=mipsel
...
dpkg-architecture would be perfect for the task, except that it is not present on other Linux distributions.
The first problem was already addressed here: How to determine whether a given Linux is 32 bit or 64 bit?
The command
getconf LONG_BIT
properly reports 32 on my system.
But how do I determine whether it is big endian or little endian?
I figured out that config.guess can determine the difference, but it does so by running the compiler which may not be present on end user's computer. On top of that config.guess completely ignores the fact that operating system works in 32-bit mode and wrongly reports mips64el instead of mipsel.
The file command tells you:
$ file my_binary_name
my_binary_name: ELF 32-bit LSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, with unknown capability 0xf41 = 0x756e6700, with unknown capability 0x70100 = 0x1040000, stripped
The LSB there stands for least-significant byte, meaning little endian. The output of file given a big-endian binary will be MSB, most-significant byte.
Note that MIPS has 3 ABIs (actually more), one of which is n32. n32 has native 64-bit integers but only 32-bit pointers (and requires a 64-bit kernel).
For n32 binaries file will still report 32-bit:
ELF 32-bit LSB executable, MIPS, N32 MIPS-III version 1 (SYSV)
o32 (what debian uses):
ELF 32-bit LSB executable, MIPS, MIPS-III version 1 (SYSV)
n64:
ELF 64-bit LSB executable, MIPS, MIPS-III version 1 (SYSV)
lscpu should work.
For example:
# lscpu
Architecture: mips
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 2
Core(s) per socket: 2
Socket(s): 1
I realise this is an old question, but it's unanswered so here goes.
You already know the bit size, so surely you can check:
case "$var" in
mips64el | mipsel) endian=little;;
mips64 | mips) endian=big;; # or: echo big;; if you need to capture it
(where $var holds your string as given: note you can pattern-match in case; see:
the POSIX sh documentation.)
If not, you should be able to test for a define from autoconf; use the MIPSEL macro.

Linux program in FreeBSD

Trying to run my program in FreeBSD OS, I have the following results:
$ ./myprogram
ELF binary type "0" not known
./myprogram: 1: Syntax error: "&" unexpected (expecting ")")
$ file myprogram
myprogram: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
dynamically linked (uses shared libs), for GNU/Linux 2.6.15,
not stripped
The program is built In GCC on Ubuntu computer. What can I do? Can I build the program for FreeBSD on my Ubuntu computer by changing some build options, or I need to build it in FreeBSD OS? Maybe there is some way to convert executable to format recognized by FreeBSD?
You can run a lot of Linux programs on FreeBSD, see http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/linuxemu.html.
If this doesn't work, the easiest solution would be to recompile your program on FreeBSD.
2021-06-21: This answer is outdated. As of 2021, FreeBSD includes Linux® binary compatibility, which will run most Linux binaries, save for those which "overly use i386™ specific calls, as enabling virtual 8086 mode".
A large number of Linux programs can be compiled on BSD systems however they are not the same operating system. Linux and BSD are technically not binary compatible.
These days BSD ships with an ABI (Application Binary Interface) for Linux which will translate Linux sys-calls on the fly (Much how WINE operates). This will allow you to run Linux ELF binaries on BSD systems with a small performance penalty.
That being said, they are not the same operating system and your best bet would be to compile for the target system either by gaining access to it or using a method of cross compiling.
Try branding the executable as a linux executable using brandelf (you still need all the dependent libraries setup though, or try linking it statically
http://www.freebsd.org/cgi/man.cgi?query=brandelf&apropos=0&sektion=0&manpath=FreeBSD+8.0-RELEASE&format=html
brandelf -t "Linux" and it should work.

Resources