Linker error when calling printf from _start
Cause of Your Error
The reason you get undefined reference to printf
while linking is because you didn't link against the C library. As well, when using your own _start
label as an entry point there are other issues that must be overcome as discussed below.
Using LIBC without C Runtime Startup Code
To make sure you are using the appropriate dynamic linker at runtime and link against the C library you can use GCC as a frontend for LD. To supply your own _start
label and avoid the C runtime startup code use the -nostartfiles
option. Although I don't recommend this method, you can link with:
gcc -m64 -nostartfiles main.o -o main
If you wish to use LD you can do it by using a specific dynamic linker and link against the C library with -lc
. To link x86_64 code you can use:
ld -melf_x86_64 --dynamic-linker=/lib64/ld-linux-x86-64.so.2 main.o -lc -o main
If you had been compiling and linking for 32-bit, then the linking could have been done with:
ld -melf_i386 --dynamic-linker=/lib/ld-linux.so.2 main.o -lc -o main
Preferred Method Using C Runtime Startup Code
Since you are using the C library you should consider linking against the C runtime. This method also works if you were to create a static executable. The best way to use the C library is to rename your _start
label to main
and then use GCC to link:
gcc -m64 main.o -o main
Doing it this way allows you to exit your program by returning (using RET) from main
the same way a C program ends. This also has the advantage of flushing standard output when the program exits.
Flushing output buffers / exit
Using syscall
with EAX=60 to exit won't flush the output buffers. Because of this you may find yourself having to add a newline character on your output to see output before exiting. This is still not a guarantee you will see what you output with printf
. Rather than the sys_exit SYSCALL you might consider calling the C library function exit
. the MAN PAGE for exit
says:
All open stdio(3) streams are flushed and closed. Files created by tmpfile(3) are removed.
I'd recommend replacing the sys_exit SYSCALL with:
extern exit
xor edi, edi ; In 64-bit code RDI is 1st argument = return value
call exit
C Program, linker error
There's no print
function in standard C. The function you are looking for is printf
(f here is short for formatted.
printf("Merry Christmas and happy holidays!");
Linker error while trying to use assembler code in cpp module
If you read the error message you will see that the function it can not find is named _sayHello
. Note the leading underscore.
To solve your problem you must name your assembler function with a leading underscore:
global _sayHello
_sayHello:
...
Linking an assembler program: error undefined reference to `printf'
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
Related Topics
Python3 Mlpy Installation Error - 'Py_Initmodule3' Was Not Declared in This Scope
Diff (Gnu Diffutils) 3.6 Exclude Directory
How to Find Common Rows in Multiple Files Using Awk
Ha Proxy Simple Forwarding with Docker
How to Run a Cron Job at Every 5 Hour Interval
Sending Mail Body and Attachment Using Mailx - Linux
Reading Input from Keyboard with X64 Linux Syscalls (Assembly)
Syntax Error of ";; Unexpected" on Simple Init Script for Debian
Bash Leftpad String with Spaces Inside Variable
Re-Encoding Only Images of a PDF? (Or, Ghostscript Fails on 8-Bit Rgb While Optimizing)
Osx/Linux, Slow Down the Output from Terminal
Bash Script - "Tar Czf ..." Command Ignore Parameters
Using Pipe in Linux Using Parent and Child Process
What Is an Absolute Pathname VS a Relative Pathname
How to Mount a Directory Inside a Docker Container on Linux Host