首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >printf@plt与puts@plt的区别

printf@plt与puts@plt的区别
EN

Stack Overflow用户
提问于 2016-08-17 22:07:04
回答 3查看 3.2K关注 0票数 6

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

代码语言:javascript
复制
#include <stdio.h>
void main(void) {
    printf("Hello World\n");
}

在汇编代码中,它给出了这条线:

代码语言:javascript
复制
0x08048424 <+25>:   call   0x80482e0 <puts@plt>

但是,当我在下面的代码中反汇编它的printf函数中有一个整数时:

代码语言:javascript
复制
#include <stdio.h>
void main(void) {
    int a = 1;
    printf("Hello Word %d\n", a);
}

它给出了这一行:

代码语言:javascript
复制
0x0804842e <+35>:   call   0x80482e0 <printf@plt>

printf@plt和put@plt之间有什么区别?

为什么反汇编程序不识别没有整数参数的printf函数?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-08-17 22:10:26

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

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

你的案子就是这样的。第一次调用printf并不需要任何printf-specific特性。您向printf提供的格式字符串非常简单:其中没有转换说明符。编译器认为,对printf的第一次调用与对puts的等效调用提供更好的服务。

同时,您对printf的第二次调用使用了printf格式字符串,即它依赖于printf-specific特性。

(从2005年开始,对这一具体问题进行了相当深入的研究:printf.html)

票数 14
EN

Stack Overflow用户

发布于 2016-08-17 22:13:09

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

代码语言:javascript
复制
man 3 printf
man 3 puts

假设您在安装了手册页的类似Unix的系统上。(没有man printf3将显示printf命令;您需要printf函数。)

您的编译器能够优化调用。

代码语言:javascript
复制
printf("Hello, world\n");

相当于:

代码语言:javascript
复制
puts("Hello, world");

因为它知道这两个函数都做什么,所以它可以确定它们所做的事情完全相同。

它不能优化

代码语言:javascript
复制
printf("Hello Word %d\n", a);

因为a的值在编译时是未知的,所以它不会打印固定的字符串。(通过观察a在初始化后从未被修改过,可以在更高的优化级别上解决这个问题)。

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

(顺便说一句,void main(void)是不正确的;使用int main(void)。)

票数 4
EN

Stack Overflow用户

发布于 2016-08-17 22:43:51

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

我正在拆卸一个程序,并看到它有printfputs的存根

代码语言:javascript
复制
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,那么一个存根和唯一存根位于同一个地址并不奇怪。我刚刚分解的程序同时调用了printfputs,因此两者都有存根,因此它们有不同的地址。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39007002

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档