Search code examples
gccassemblyx86linker-errorsld

Errors when linking 32/64bit assembly in Linux


I am new to assembly language programming. I am trying to follow the steps outlined here to get a better understanding of assembly and optimization. My operating system is Linux Mint, and I am trying to use the NASM assembler, albeit unsuccessfully.

As in the walkthrough, the code is:

BITS 32
GLOBAL main
SECTION .text
main:
    mov eax, 42
    ret

It compiles successfully with nasm using the command: nasm -f elf tiny.asm

But if I try to use gcc to link with the command: gcc -Wall -s tiny.o

I get the following error: /usr/bin/ld: i386 architecture of input file `tiny.o' is incompatible with i386:x86-64 output

A quick search told me that I should link using this ld command: ld -m elf_i386 -s -o tiny tiny.o

However, doing this gives me the following warning: ld: warning: cannot find entry symbol _start; defaulting to 0000000008048060

And if I ./tiny I get a Segmentation Fault. And ./tiny ; echo $? also returns the number '139' which is... unexpected.

Browsing around, I see that the problem is solved for some by passing 1 to the eax register and 0 to ebx, and using an int command I'm unfamiliar with to end the program... But considering my objective is to make the program as small as possible, I would rather not add additional lines of code.

I should add that compiling and linking this similar code (GAS):

.global main
.text
main:
    mov $32, %eax

Using the gcc compiler seems to run flawlessly. I'm at a loss here. Any point in the right direction would be greatly appreciated.


Solution

  • This applies to Linux Mint, Ubuntu, Xubuntu and other modern Ubuntu based distributions. For other Debian systems the information is the same, but you can remove the sudo command from the installation command and run the command as the root user.


    By default files needed for GCC to create 32-bit program are not installed on 64-bit Linux Mint. This command will install the required files:

    sudo apt-get install gcc-multilib g++-multilib 
    

    To assemble asa 32-bit object, and then link to a 32-bit executable you can do this:

    nasm -f elf32 tiny.asm -o tiny.o
    gcc -m32 -Wall -s tiny.o -o tiny
    

    Since you had BITS 32 at the top of the assembler file you want to compile that to a 32-bit ELF object which is what the -f elf32 option on the NASM command line does.

    GCC is used to link objects to a final executable. The addition of -m32 tells GCC to link the objects to a 32-bit executable. The -m32 option overrides the normal default behavior of generating 64-bit executables on a 64-bit Linux distribution.


    By using GCC to link the executable, the generated program actually supplies a _start that does C runtime initialization and then calls the label called main as if it was a C function.

    When you do the ret in your main function it returns back to the C runtime code and exits the program cleanly for you.

    Using GCC is the easier and safer method for new assembly language developers. It also allows you to add code that calls the C runtime functions like printf, scanf, atoi and most of the other standard C library functions.