printf @ plt和puts @ plt

时间:2016-08-17 22:07:04

标签: c disassembly

我通过反汇编一些C代码来学习汇编语言。当我用GDB反汇编这个基本的C代码时:

#include <stdio.h>
void main(void) {
    printf("Hello World\n");
}

在汇编代码中,它给出了这一行:

0x08048424 <+25>:   call   0x80482e0 <puts@plt>

但是,当我在printf函数中具有整数的代码下面进行反汇编时:

#include <stdio.h>
void main(void) {
    int a = 1;
    printf("Hello Word %d\n", a);
}

它给出了这一行:

0x0804842e <+35>:   call   0x80482e0 <printf@plt>

printf @ plt和puts @ plt有什么区别?

为什么反汇编程序在没有整数参数的情况下无法识别printf函数?

3 个答案:

答案 0 :(得分:9)

在GCC中printfputs是内置函数。这意味着编译器完全了解它们的语义。在这种情况下,如果编译器认为它将产生更好(更快和/或更紧凑)的代码,则可以自由地用对另一个函数的等效调用替换对一个函数的调用。

puts通常是一种更有效的函数,因为它不需要解析和解释格式字符串。

这正是你案件中发生的事情。您第一次拨打printf并不需要任何printf特定功能。您提供给printf的格式字符串很简单:它没有转换说明符。编译器认为,通过对printf的等效调用,可以更好地为puts拨打电话。

与此同时,您第二次拨打printf可以轻松使用printf格式字符串,即它依赖于printf特定功能。

(2005年对这一具体问题的一些相当彻底的研究:http://www.ciselant.de/projects/gcc_printf/gcc_printf.html

答案 1 :(得分:4)

我不知道@plt部分,但printfputs只是两个不同的标准库函数。 printf采用格式字符串和零个或多个其他参数,可能是不同类型的参数。 puts只需一个字符串并打印出来,然后换行。有关更多信息,请参阅任何C参考,或键入

man 3 printf
man 3 puts

假设您使用的是安装了手册页的类Unix系统。 (man printf没有3会显示printf 命令;您需要printf 功能。)< / p>

您的编译器能够优化呼叫

printf("Hello, world\n");

相当于:

puts("Hello, world");

因为它知道两个函数的作用,所以它可以确定它们完全相同。

无法优化

printf("Hello Word %d\n", a);

因为a的值在编译时是未知的,所以它不会打印固定的字符串。 (通过观察a在初始化后永远不会被修改,它可能会在更高的优化级别上找出它。)

反汇编程序只是向您展示编译器生成的代码。

(顺便提一下,void main(void)不正确;请使用int main(void)。)

答案 2 :(得分:2)

putsprintf函数似乎具有相同的地址,因为您正在查看存根,而不是真正的函数。这些存根从过程链接表中加载一个地址(@plt后缀所指的内容),然后调用它。

我反汇编程序,发现它有printfputs的存根:

08048370 <printf@plt>:
 8048370:       ff 25 04 a0 04 08       jmp    *0x804a004
 8048376:       68 08 00 00 00          push   $0x8
 804837b:       e9 d0 ff ff ff          jmp    8048350 <_init+0x3c>

08048380 <puts@plt>:
 8048380:       ff 25 08 a0 04 08       jmp    *0x804a008
 8048386:       68 10 00 00 00          push   $0x10
 804838b:       e9 c0 ff ff ff          jmp    8048350 <_init+0x3c>

如您所见,实际函数位于其他位置,并且这些存根仅为程序实际使用的函数生成。如果您的程序只调用一个函数,然后将其从printf更改为puts,那么唯一的存根位于同一地址并不令人惊讶。我刚刚反汇编的程序调用{​​{1}}和printf,因此两者都有存根,因此它们有不同的地址。