1

Trying to run linux NASM printf() on https://godbolt.org/z/G66bdzoof, but it's returning this error:

ASM generation compiler returned: 0 /usr/bin/ld: /app/example.o:/app/example.asm:14: undefined reference to `printf' Execution build compiler returned: 1

extern printf

global _start

section .data
    message db "Hello World!", 10, 0

section .text

_start:

    ; print message
    push dword message
    call printf 
    add esp, 4 

    ; exit with code 0
    mov eax,1
    mov ebx,0
    int 80h

Question

Are there some kind of compiler options missing?

The godbolt example is using these compilation options:

-g -f elf -F stabs /tmp/compiler-explorer-compiler2022626-8227-fdi87r.9yqas/example.asm
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
vengy
  • 1,548
  • 10
  • 18
  • Please show the exact commands you typed to assemble and link your code. Most likely you forgot to link in the libc. Note also that when you link in the libc, you should start your program with `main` instead of `_start` and link through the C compiler so the C runtime is initialised correctly. – fuz Jul 26 '22 at 15:59

1 Answers1

1

The problem isn't assembling, NASM executes fine. The problem is linking, with ld. The Compiler Explorer build is linking into a static executable without libraries, presumably just ld -m elf_i386 -o foo foo.o

The Compiler Explorer UI only gives you control over nasm options, not ld options, so you can't pass -lc to link the C library. If you use the "library' dropdown on Godbolt, it says "no libraries are configured for this language". (vs. for C++, there are libs like Google::Benchmark you can add tell it to link with; some of the libraries are not header-only, so must actually generate linker options).


You're going to want to use a debugger to single-step your code anyway, so install a dev setup locally. https://www.onlinegdb.com/ has assembly support, but only GCC (so GAS syntax, AT&T or Intel but not with NASM directives).

And yes, using a debugger is basically essential. Without that you're just wasting your own time (and everyone else's if you ask other people to spend time looking at code you haven't single-stepped yourself). It's like trying to build a robot blindfolded. See the bottom of the x86 tag wiki for asm debugging tips for Linux or Windows. (Your current program will only work on Linux; it uses the 32-bit int 0x80 system-call ABI to exit.)


Normally you'd want to write a main if you're using C library functions, and don't use a raw _exit system-call if using stdio functions like printf. With output to a pipe or network socket (not a terminal), stdout will be full-buffered not line-buffered, so you'll get no output when you _exit without calling fflush.

But linking with libc will work even when you write your own _start (skipping the CRT startup code), if you dynamically link, not static. glibc on Linux has dynamic linker hooks that let it initialize itself before _start runs (unlike on some other systems, e.g. cygwin), but if you statically link then your _start is truly the first instructions that run in user-space. Calling functions like printf that depend on data structures like global stdout will crash.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Thanks. I was being lazy by not installing nasm onto my WSL 2 (windows subsystem for linux) dev environment and hoping there was a quick and dirty online replacement. Anyhow, thanks for the tips about godbolt.org not giving control over the linker ld options. Now running: sudo apt install nasm – vengy Jul 26 '22 at 16:33
  • Interestingly on Windows, calling `puts` directly without *any* initialization from `msvcrt.dll` just works (at least on Windows 10 a few months a go), so probably `printf` works too. – xiver77 Jul 26 '22 at 16:34