Gcc printf编译器优化?can';找不到%s";堆栈上gdb中的字符
当我的程序在gdb中反汇编时,我可以看到buf的地址被推到堆栈上,但我看不到格式字符串被推到堆栈上。为什么会这样?这是一个聪明的编译器优化吗 我尝试编译printf语句的一些不同变体,看看是否可以模拟未被推送到堆栈上的“%s”字符串(或其地址),但我做不到 这是程序代码:Gcc printf编译器优化?can';找不到%s";堆栈上gdb中的字符,gcc,compiler-construction,gdb,printf,Gcc,Compiler Construction,Gdb,Printf,当我的程序在gdb中反汇编时,我可以看到buf的地址被推到堆栈上,但我看不到格式字符串被推到堆栈上。为什么会这样?这是一个聪明的编译器优化吗 我尝试编译printf语句的一些不同变体,看看是否可以模拟未被推送到堆栈上的“%s”字符串(或其地址),但我做不到 这是程序代码: int main(int argc, char **argv) { char buf[128]; if(argc < 2) return 1; strcpy(buf, argv[1]);
int main(int argc, char **argv) {
char buf[128];
if(argc < 2) return 1;
strcpy(buf, argv[1]);
printf("%s\n", buf);
return 0;
}
int main(int argc,char**argv){
char-buf[128];
如果(argc<2)返回1;
strcpy(buf,argv[1]);
printf(“%s\n”,buf);
返回0;
}
使用gcc 4.5.2、32位linux编译是的,gcc似乎将丢弃“printf”(%s\n,buff)”而代之以“put()”:
以下答案适用于x86 64位汇编程序 简短回答:x86没有%s作为某种汇编指令,这是纯c语言,甚至是现在的java语言 长答覆:
- 用符号编译程序(非剥离):
gcc-g yourprogram.c
- 使用混合c代码转储程序集:
objdump-S yourProgram.o
strcpy(buf, argv[1]);
4005eb: 48 8b 85 60 ff ff ff mov -0xa0(%rbp),%rax
Move argv[0] to %rax register
4005f2: 48 83 c0 08 add $0x8,%rax
Add 8 to %rax which means we now store argv[1]
4005f6: 48 8b 10 mov (%rax),%rdx
Copy argv[1] to the destination register %rdx
4005f9: 48 8d 85 70 ff ff ff lea -0x90(%rbp),%rax
Move buf to %rax
400600: 48 89 d6 mov %rdx,%rsi
Move argv[1] to %esi which is the source register implicitly used by string funcs
400603: 48 89 c7 mov %rax,%rdi
Move buf to destination register
400606: e8 85 fe ff ff callq 400490 <strcpy@plt>
Call strcpy which uses %rsi and %rdi
Now we have argv[1] in buf, right!?
printf("%s\n", buf);
40060b: 48 8d 85 70 ff ff ff lea -0x90(%rbp),%rax
The first line loads what you have at the base pointer -0x90 to the %rax register which means that it loads the address of buf into rax as buf is on the stack.
400612: 48 89 c7 mov %rax,%rdi
Just mov it to the %rdi register.
400615: e8 86 fe ff ff callq 4004a0 <puts@plt>
Call the puts function with buf
strcpy(buf,argv[1]);
4005eb:48 8b 85 60 ff ff mov-0xa0(%rbp),%rax
将argv[0]移动到%rax寄存器
4005f2:48 83 c0 08添加$0x8,%rax
将8添加到%rax,这意味着我们现在存储argv[1]
4005f6:48 8b 10 mov(%rax),%rdx
将argv[1]复制到目标寄存器%rdx
4005f9:48 8d 85 70 ff ff ff lea-0x90(%rbp),%rax
将buf移动到%rax
400600:4889D6MOV%rdx%rsi
将argv[1]移动到%esi,它是字符串funcs隐式使用的源寄存器
400603:48 89 c7 mov%rax,%rdi
将buf移到目标寄存器
400606:e8 85 fe ff ff callq 400490
调用使用%rsi和%rdi的strcpy
现在我们有了buf中的argv[1],对吧!?
printf(“%s\n”,buf);
40060b:48 8d 85 70 ff ff lea-0x90(%rbp),%rax
第一行将基指针-0x90处的内容加载到%rax寄存器,这意味着当buf位于堆栈上时,它将buf的地址加载到rax中。
400612:48 89 c7 mov%rax,%rdi
只需将其移动到%rdi寄存器。
400615:e8 86 fe ff ff callq 4004a0
使用buf调用puts函数
那么它可以通过寄存器传递吗?也许它优化为一个sys_write系统调用?Thanx用于共享-我从来都不知道gcc会这样做(用“puts()”代替“printf()”)。但很明显,它可以——而且确实如此:)哇,我真的没在想。非常感谢。出于某种原因,我仍然认为puts采用了%s参数。也许我需要暂时停止使用电脑。。。
#include <stdio.h>
#include <string.h>
int
main(int argc, char **argv)
{
char buf[128];
if(argc < 2)
return 1;
strcpy(buf, argv[1]);
printf("%s\n", buf);
return 0;
}
.file "tmp.c"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $148, %esp
movl %ecx, -140(%ebp)
movl -140(%ebp), %eax
cmpl $1, (%eax)
jg .L2
movl $1, -136(%ebp)
jmp .L4
.L2:
movl -140(%ebp), %edx
movl 4(%edx), %eax
addl $4, %eax
movl (%eax), %eax
movl %eax, 4(%esp)
leal -132(%ebp), %eax
movl %eax, (%esp)
call strcpy
leal -132(%ebp), %eax
movl %eax, (%esp)
call puts
movl $0, -136(%ebp)
.L4:
movl -136(%ebp), %eax
addl $148, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-48)"
.section .note.GNU-stack,"",@progbits
strcpy(buf, argv[1]);
4005eb: 48 8b 85 60 ff ff ff mov -0xa0(%rbp),%rax
Move argv[0] to %rax register
4005f2: 48 83 c0 08 add $0x8,%rax
Add 8 to %rax which means we now store argv[1]
4005f6: 48 8b 10 mov (%rax),%rdx
Copy argv[1] to the destination register %rdx
4005f9: 48 8d 85 70 ff ff ff lea -0x90(%rbp),%rax
Move buf to %rax
400600: 48 89 d6 mov %rdx,%rsi
Move argv[1] to %esi which is the source register implicitly used by string funcs
400603: 48 89 c7 mov %rax,%rdi
Move buf to destination register
400606: e8 85 fe ff ff callq 400490 <strcpy@plt>
Call strcpy which uses %rsi and %rdi
Now we have argv[1] in buf, right!?
printf("%s\n", buf);
40060b: 48 8d 85 70 ff ff ff lea -0x90(%rbp),%rax
The first line loads what you have at the base pointer -0x90 to the %rax register which means that it loads the address of buf into rax as buf is on the stack.
400612: 48 89 c7 mov %rax,%rdi
Just mov it to the %rdi register.
400615: e8 86 fe ff ff callq 4004a0 <puts@plt>
Call the puts function with buf