Search code examples
linuxassemblyx86linkermultiarch

Assemble and run i386 asm program on x86-64 Linux with as and ld


So I'm new trying asm and I want to compile a little program that just exits with i386 instructions instead of x86-64 ones. I have a x86-64 Ubuntu which compile and run x86-64 one perfectly but I don't get it how to assemble and link the i386 version on the same x86-64 machine (I have installed i386 compat).

I know there are similar questions answered already, But none of them use as and ld to do it so I don't know exactly how could I translate those solutions to my problem.

For the x86-64 I use as and ld as follows:

#       Assemble: as exit.s -o exit.o
#        Linking: ld exit.o -o exit

The x86-32 version of the program:

.section .data
.section .text
.globl _start
_start:
    movl $1, %eax
    movl $0, %ebx
    int $0x80

Now.. I've been searching how to do it and found about the --32 in as and the -m {arg} in ld but every time I get to compile it without arch errors it gives me the "File in wrong format" error.

I've tried doing ld with elf_i386 and i386linux like this:

as --32 exit.s -o exit.o
ld -m elf_i386 exit.o -o exit
#Error: -bash: ./exit: cannot execute binary file: File in wrong format
ld -m i386linux exit.o -o exit
#Error: -bash: ./exit: cannot execute binary file: File in wrong format

I want to add that for compatibility I've installed these packages listed in the Ubuntu help forum:

sudo dpkg --add-architecture i386
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386
sudo apt-get install multiarch-support

Solution

  • Those are the correct commands for assembling and linking a 32-bit static executable. (Assembling 32-bit binaries on a 64-bit system (GNU toolchain))

    Looks like your kernel was built without CONFIG_COMPAT_BINFMT_ELF List of executable formats on Linux, so it doesn't recognize 32-bit ELF static executables as executable. (I think that's the relevant Linux kernel config option.)


    Or you're using the Windows Subsystem version 1 for Linux, which also doesn't support 32-bit executable.

    WSL v1 doesn't support the 32-bit int 0x80 ABI from 64-bit processes, either, so that also won't work. (What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?). It's like a Linux kernel without CONFIG_IA32_EMULATION.

    See Does WSL 2 really support 32 bit program? for how to make sure you're really using WSL2, which is a real Linux kernel in a VM, and thus allows 32-bit user-space.


    libc packages are irrelevant for this. You're making a static executable which doesn't depend on any other files to run.

    After running your build commands on my Arch Linux system, I get:

    $ as --32 exit.s -o exit.o
    $ ld -m elf_i386 exit.o -o exit
    $ file exit
    exit: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
    $ ./exit ; echo $?
    0
    

    So it works fine, your system is just broken somehow. It's either not real Ubuntu, or you have a custom kernel.