2011-12-10 16 views
3

當我的程序在gdb被拆開,我可以看到BUF的地址被壓入堆棧,但我沒有看到的格式字符串推到它。這是爲什麼?這是一個聰明的編譯器優化?printf編譯器優化?找不到在gdb「%s」字符的堆棧上

我試過編譯printf語句的幾個不同變體,以查看我是否可以模仿未被壓入堆棧的「%s」字符串(或其地址),但我無法做到。

這是程序代碼:

int main(int argc, char **argv) { 

    char buf[128]; 
    if(argc < 2) return 1; 

    strcpy(buf, argv[1]); 

    printf("%s\n", buf); 

    return 0; 
} 

用gcc編譯4.5.2,32位Linux

+0

是否可以通過寄存器呢? – dasblinkenlight

+0

也許它優化了一個sys_write系統調用? –

+0

Thanx for sharing - 我從來不知道gcc會這麼做(用「printf()」替代「puts()」)。但顯然它可以 - 並且:) – paulsm4

回答

7

是的,看來GCC將扔掉的 「printf(」 %S \ n」, BUFF)」而代以 「看跌期權()」 在其位:

vi tmp.c => 
#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; 
} 

$ GCC -S -Wall -pedantic tmp.c 更少tmp.s =>

 .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 
+0

哇,我真的沒有想到。謝謝。出於某種原因,我仍然有這樣的想法,即提出了一個%s的論點。也許我需要裁掉一些電腦... –

1

以下的答案適用於86的64位彙編。

簡短的回答:86不具備%S爲某種彙編指令,即純C和連渣時下以及。

龍答:

  • 與符號編譯程序(非剝離):gcc -g yourprogram.c

  • 轉儲混雜的C代碼的組件:objdump -S yourProgram.o

下面的文字顯示如何在裝配中顯示strcpyprintf。我還添加了如何閱讀程序集:

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 <[email protected]> 
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 <[email protected]> 
Call the puts function with buf