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
CodePudding user response:
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.