I've been learning assembly language by disassembling some C code. When I disassemble this basic C code with GDB:
#include <stdio.h>
void main(void) {
printf("Hello World\n");
}
Among assembly code, it gives this line:
0x08048424 <+25>: call 0x80482e0 <puts@plt>
However, when I disassemble below code which has an integer in printf function:
#include <stdio.h>
void main(void) {
int a = 1;
printf("Hello Word %d\n", a);
}
It gives this line:
0x0804842e <+35>: call 0x80482e0 <printf@plt>
What is the difference between printf@plt and puts@plt?
Why disassembler does not recognize printf function without an integer parameter?
PLT means Procedure Linkage Table. It is a special technique used in ELF files to localize fixing up at load time on machines where relative addressing is available. The function you're calling is located in another module (typically, libc.
The big difference between the two functions, at the assembly level, is that the puts() function will just take one argument (a pointer to the string to display) and the printf() function will take one argument (a pointer to the format string) and, then, an arbitrary number of arguments in the stack ( printf() is a ...
The PLT is the procedure linkage table, one of the structures which makes dynamic loading and linking easier to use. printf@plt is actually a small stub which (eventually) calls the real printf function, modifying things on the way to make subsequent calls faster.
In GCC printf
and puts
are built-in functions. Which means that the compiler has full knowledge of their semantics. In such cases the compiler is free to replace a call to one function with an equivalent call to another, if it thinks that it will produce better (faster and/or more compact) code.
puts
is a generally more efficient function since it does not have to parse and interpret a format string.
This is exactly what happened in your case. Your first call to printf
does not really need any printf
-specific features. The format string you supplied to printf
is trivial: it has no conversion specifiers in it. The compiler thought that your first call to printf
is better served with an equivalent call to puts
.
Meanwhile, your second call to printf
makes non-trivial use of printf
format string, i.e. it relies on printf
-specific features.
(Some rather thorough research of this specific matter from 2005: http://www.ciselant.de/projects/gcc_printf/gcc_printf.html)
I don't know about the @plt
part, but printf
and puts
are simply two different standard library functions. printf
takes a format string and zero or more other parameters, possibly of different types. puts
takes just a string and prints it, followed by a newline. Consult any C reference for more information, or type
man 3 printf
man 3 puts
assuming you're on a Unix-like system with man pages installed. (man printf
without the 3
will show you the printf
command; you want the printf
function.)
Your compiler is able to optimize the call
printf("Hello, world\n");
to the equivalent of:
puts("Hello, world");
because it knows what both functions do, so it can determine that they do exactly the same thing.
It can't optimize
printf("Hello Word %d\n", a);
because the value of a
is unknown at compile time, so it doesn't print a fixed string. (It might figure it out at higher optimization levels by observing that a
is never modified after its initialization).
The disassembler is merely showing you the code generated by the compiler.
(Incidentally, void main(void)
is incorrect; use int main(void)
.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With