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

2

5

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?

Barnie answered 19/12, 2015 at 19:36 Comment(2)
I think the error message is pretty clear: i386 architecture is incompatible with i386:x86-64.Istle
It also looks like it wants your entry point to be named "start" rather than "main"Arrival
L
16

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
Lately answered 19/12, 2015 at 20:25 Comment(5)
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`Barnie
@Barnie 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)Lately
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 youBarnie
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.Lately
I just needed to input two numbers. Works fine.Barnie
C
3

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

Cirri answered 19/12, 2015 at 20:13 Comment(1)
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?Brittne

© 2022 - 2024 — McMap. All rights reserved.