Linking an assembler program: error "undefined reference to `printf'"

26,290

Solution 1

You have a couple of options

  • Use LD to link to a final executable
  • Use GCC to link to a final executable

Using LD Method

Your command lines use LD, unfortunately that presents a number of problems. The first:

ld: i386 architecture of input file `0_strange_calc.o' is incompatible with i386:x86-6

You are on 64-bit Debian, trying to produce a 32-bit executable. -f elf on the NASM command line generates 32-bit ELF (-f elf64 generate 64 bit objects). Your LD command line is by default trying to generate a 64-bit executable thus the error above is given. You can force LD to generate a 32-bit executable by adding the -m elf_i386 option to LD's command line.

ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0

You should tell LD that your entry point is main . LD by default looks for an entry point of _start. You can add -e main to the LD command line to resolve that.

Errors like this suggest you need the C library (where printf exists):

0_strange_calc.asm:(.text+0x8): undefined reference to `printf'

Since your code doesn't use printf directly I can only assume that is required by the functions in training.s . In order to link in the C library you will need to add it after the .o files in your command line. You can do this with -lc on your LD command line. You'll also need to tell LD specifically what dynamic linker library you will need to use (In this case a 32-bit one). In a Debian environment that will usually look like: -dynamic-linker /lib/ld-linux.so.2

So your NASM and LD lines should look like this:

nasm -f elf -g 0_strange_calc.asm
ld -melf_i386 -e main -dynamic-linker /lib/ld-linux.so.2 -o 0_strange_calc  0_strange_calc.o -lc

Using GCC Method

You can simplify linking to the C library by using GCC to link you your object file to an executable. To build a 32-bit executable you could use:

nasm -f elf -g 0_strange_calc.asm
gcc -m32 0_strange_calc.o -o 0_strange_calc

The C library and runtime has a _start method that does C startup initialization and in turn calls a function called main which happens to be the function in your assembly file. -m32 tells GCC you are also linking to a 32-bit executable.


Special Considerations

You may also need to to install the Multlilib versions of gcc (and g++ if you want to) so that you can properly build and run 32-bit applications on 64-bit Debian using the appropriate C libraries. That can be done with this command line:

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

On Ubuntu based systems you'd need to use:

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

Solution 2

Note that the problem is not the asm code but a missing imported function. If you read training.s you will see the definition of printeax and other methods as well. Moreover you will see that some of those method use external function like printf which is of course not asm function but some imported language lib

BITS 32
extern printf
extern exit
extern scanf
extern read

So in order to make it work - i.e to find those external libs ( you have also warning there that you should handle but this is out of this scope). You need to use the linker properly. According to Frank at the nasm board you have two options

  1. use the ld linker but tell it to use c lib via lc options. i.e: ld -ld -o 0_strange_calc 0_strange_calc.o -lc. More info can be found here

  2. use the gcc linker.

P.S Note that also the code uses 32bit which on your computer produce a warning as you can use 64 bit and you use elf flag. More on it you can find at the nasm docs

Share:
26,290
Kaka
Author by

Kaka

Updated on December 20, 2020

Comments

  • Kaka
    Kaka over 3 years

    I'm trying to compile this x86 assembly code on x64 Debian :

    BITS 32
    
    %include    'training.s' 
    
    global main
    extern  exit    
    
    ; ===============================================
    section .text
    
    main:
        ; The program begins here:
    
        call    read_hex    
        mov     edx,eax
        call    read_hex    
        add     eax,edx
        add     eax,eax
        inc     eax         
    
        call    print_eax   
    
        ; Exit the process:
        push    0
        call    exit
    

    I'm getting these errors:

    ~$nasm -f elf -g 0_strange_calc.asm && ld -o 0_strange_calc 0_strange_calc.o
        ld: i386 architecture of input file `0_strange_calc.o' is incompatible with i386:x86-64 output
        ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
        0_strange_calc.o:training.s:25: undefined reference to `printf'
        0_strange_calc.o:training.s:35: undefined reference to `printf'
        0_strange_calc.o:training.s:45: undefined reference to `printf'
        0_strange_calc.o:training.s:56: undefined reference to `read'
        0_strange_calc.o:training.s:77: undefined reference to `scanf'
        0_strange_calc.o:training.s:97: undefined reference to `scanf'
        0_strange_calc.o:training.s:108: undefined reference to `printf'
        0_strange_calc.o:training.s:129: undefined reference to `printf'
        0_strange_calc.o:training.s:137: undefined reference to `printf'
        0_strange_calc.o:0_strange_calc.asm:50: undefined reference to `exit'
    
    
    
    
     ~$ yasm -f elf64 0_strange_calc.asm
        ~$ gcc -m32 -nostdlib -nostdinc 0_strange_calc.o -o 0_strange_calc
        /usr/bin/ld: i386:x86-64 architecture of input file `0_strange_calc.o' is incompatible with i386 output
        /usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 00000000080480c0
        0_strange_calc.o: In function `no symbol':
        0_strange_calc.asm:(.text+0x8): undefined reference to `printf'
        0_strange_calc.asm:(.text+0x19): undefined reference to `printf'
        0_strange_calc.asm:(.text+0x2a): undefined reference to `printf'
        0_strange_calc.asm:(.text+0x39): undefined reference to `read'
        0_strange_calc.asm:(.text+0x5b): undefined reference to `scanf'
        0_strange_calc.asm:(.text+0x7a): undefined reference to `scanf'
        0_strange_calc.asm:(.text+0x89): undefined reference to `printf'
        0_strange_calc.asm:(.text+0xa8): undefined reference to `printf'
        0_strange_calc.asm:(.text+0xb9): undefined reference to `printf'
        0_strange_calc.o: In function `main':
        0_strange_calc.asm:(.text+0xdb): undefined reference to `exit'
        collect2: error: ld returned 1 exit status
    

    This is my dump of 0_strange_calc.o:

    ~$ objdump -M intel -d 0_strange_calc.o
    
    0_strange_calc.o:     file format elf64-x86-64
    
    
    Disassembly of section .text:
    
    0000000000000000 <main-0xc2>:
       0:   60                      (bad)  
       1:   50                      push   rax
       2:   68 00 00 00 00          push   0x0
       7:   e8 00 00 00 00          call   c <main-0xb6>
       c:   83 c4 08                add    esp,0x8
       f:   61                      (bad)  
      10:   c3                      ret    
      11:   60                      (bad)  
      12:   50                      push   rax
      13:   68 00 00 00 00          push   0x0
      18:   e8 00 00 00 00          call   1d <main-0xa5>
      1d:   83 c4 08                add    esp,0x8
      20:   61                      (bad)  
      21:   c3                      ret    
      22:   60                      (bad)  
      23:   b8 00 00 00 00          mov    eax,0x0
      28:   50                      push   rax
      29:   e8 00 00 00 00          call   2e <main-0x94>
      2e:   83 c4 04                add    esp,0x4
      31:   61                      (bad)  
      32:   c3                      ret    
      33:   60                      (bad)  
      34:   51                      push   rcx
      35:   57                      push   rdi
      36:   6a 00                   push   0x0
      38:   e8 00 00 00 00          call   3d <main-0x85>
      3d:   83 c4 0c                add    esp,0xc
      40:   31 d2                   xor    edx,edx
      42:   c6 04 07 00             mov    BYTE PTR [rdi+rax*1],0x0
      46:   61                      (bad)  
      47:   c3                      ret    
      48:   55                      push   rbp
      49:   89 e5                   mov    ebp,esp
      4b:   83 ec 04                sub    esp,0x4
      4e:   53                      push   rbx
      4f:   51                      push   rcx
      50:   52                      push   rdx
      51:   8d 5d fc                lea    ebx,[rbp-0x4]
      54:   53                      push   rbx
      55:   68 00 00 00 00          push   0x0
      5a:   e8 00 00 00 00          call   5f <main-0x63>
      5f:   83 c4 08                add    esp,0x8
      62:   8b 03                   mov    eax,DWORD PTR [rbx]
      64:   5a                      pop    rdx
      65:   59                      pop    rcx
      66:   5b                      pop    rbx
      67:   c9                      leave  
      68:   c3                      ret    
      69:   55                      push   rbp
      6a:   89 e5                   mov    ebp,esp
      6c:   83 ec 04                sub    esp,0x4
      6f:   8d 5d fc                lea    ebx,[rbp-0x4]
      72:   60                      (bad)  
      73:   53                      push   rbx
      74:   68 00 00 00 00          push   0x0
      79:   e8 00 00 00 00          call   7e <main-0x44>
      7e:   83 c4 08                add    esp,0x8
      81:   61                      (bad)  
      82:   8b 03                   mov    eax,DWORD PTR [rbx]
      84:   c9                      leave  
      85:   c3                      ret    
      86:   60                      (bad)  
      87:   56                      push   rsi
      88:   e8 00 00 00 00          call   8d <main-0x35>
      8d:   83 c4 04                add    esp,0x4
      90:   61                      (bad)  
      91:   c3                      ret    
      92:   60                      (bad)  
      93:   b9 20 00 00 00          mov    ecx,0x20
      98:   d1 c0                   rol    eax,1
      9a:   89 c2                   mov    edx,eax
      9c:   83 e2 01                and    edx,0x1
      9f:   51                      push   rcx
      a0:   50                      push   rax
      a1:   52                      push   rdx
      a2:   68 00 00 00 00          push   0x0
      a7:   e8 00 00 00 00          call   ac <main-0x16>
      ac:   83 c4 08                add    esp,0x8
      af:   58                      pop    rax
      b0:   59                      pop    rcx
      b1:   e2 e5                   loop   98 <main-0x2a>
      b3:   68 00 00 00 00          push   0x0
      b8:   e8 00 00 00 00          call   bd <main-0x5>
      bd:   83 c4 04                add    esp,0x4
      c0:   61                      (bad)  
      c1:   c3                      ret    
    
    00000000000000c2 <main>:
      c2:   e8 81 ff ff ff          call   48 <main-0x7a>
      c7:   89 c2                   mov    edx,eax
      c9:   e8 7a ff ff ff          call   48 <main-0x7a>
      ce:   01 d0                   add    eax,edx
      d0:   01 c0                   add    eax,eax
      d2:   40 e8 28 ff ff ff       rex call 0 <main-0xc2>
      d8:   6a 00                   push   0x0
      da:   e8 00 00 00 00          call   df <main+0x1d>
    

    It seems to have been converted successfully in x64 asm, other simple code I had compiled and linked without problems. What am I doing wrong? And how can I fix it?

  • Kaka
    Kaka over 8 years
    It seems to compile, but it doesn't generate any output file. I'm using this commands: ` $ nasm -f elf -g 0_strange_calc.asm ` ` ~$ ld -melf_i386 -e main -dynamic-linker /lib/ld-linux.so.2 -o strange_calc 0_strange_calc.o -lc`
  • Michael Petch
    Michael Petch over 8 years
    @Kaka The original command line I gave (I fixed it already) output to a file called strange_calc (not 0_strange_calc). That was an error on my part. Just change it to ld -melf_i386 -e main -dynamic-linker /lib/ld-linux.so.2 -o 0_strange_calc 0_strange_calc.o -lc (The output file was only thing that was wrong)
  • Kaka
    Kaka over 8 years
    Yes, it generated a file called "strange_calc". Now I manage to run it. The app doesn't seem to give any output, but I suppose this is the expected result. Thank you
  • Michael Petch
    Michael Petch over 8 years
    If it isn't printing probably a problem with your code. I don't know how print_eax works since it isn't part of the code given. But if you are linking and get an exectuable, printing being incorrect would likely be better asked in another question if you can't resolve it.
  • Kaka
    Kaka over 8 years
    I just needed to input two numbers. Works fine.
  • WENDYN
    WENDYN about 2 years
    I keep getting cannot find -lc with ld, any idea why? Is it possible that it has to do something with me using MinGW toolkit?