Search code examples
linuxassemblyx86linkernasm

Getting undefined reference to "_printf" error for assembly code despite using gcc linker


I am trying to follow the exercise in the book PC Assembly by Paul Carter. http://pacman128.github.io/pcasm/

I'm trying to run the program from 1.4 page 23 on Ubuntu 18. The files are all available on the github site above.

Since original code is for 32bit I compile using

nasm -f elf32

for first.asm and asm_io.asm to get the object files. I also compile driver.c

I use the linker from gcc and run

gcc -m32 -o first first.o asm_io.o driver.o 

but it keeps giving me a bun of errors like

undefined reference to '_scanf' undefined reference to '_printf'

(note _printf appears instead of printf because some conversion is done in the file asm_io.asm to maintain compatibility between windows and linux OS's)

I don't know why these errors are appearing. I also try running using linker directly

ld -m elf_i386 -e main -o first -first.o driver.o asm_io.o -I /lib/i386-linux-gnu/ld-linux.so.2 

and many variations since it seems that its not linking with the C libraries.

Any help? Stuck on this for a while and couldn't find a solution on similar questions


Solution

  • Linux doesn't prepend _ to names when mapping from C to asm symbol names in ELF object files1.

    So call printf, not _printf, because there is no _printf in libc.
    (Or in a PIE executable like gcc makes by default on most distros, call printf wrt ..plt)

    Whatever "compatibility" code did that is doing it wrong. Only Windows and OS X use _printf, Linux uses printf.

    So either you've misconfigured something or defined the wrong setting, or it requires updating / porting to Linux.


    Footnote 1: In ancient history (like over 20 years ago), Linux with the a.out file format did use leading underscores on symbol names.


    Update: the library uses the NASM preprocessor to %define _scanf scanf and so on, but it requires you to manually define ELF_TYPE by assembling with nasm -d ELF_TYPE.

    They could have detected ELF32 or ELF64 output formats on their own, because NASM pre-defines __OUTPUT_FORMAT__. Someone should submit a pull-request to make this detection automatic with code something like this:

    %ifidn __OUTPUT_FORMAT__, elf32
      %define  ELF_TYPE 32
    %elifidn __OUTPUT_FORMAT__, elf64
      %define  ELF_TYPE 64
    %endif
    
    
    %ifdef ELF_TYPE
    ...
    %endif