оптимизация компилятора printf?не удается найти символы "% s" в GDB в стеке - PullRequest
3 голосов
/ 10 декабря 2011

Когда моя программа разбирается в gdb, я вижу, как адрес buf помещается в стек, но я не вижу строки форматирования, помещенной в него. Любая причина, почему это? Это умная оптимизация компилятора?

Я попытался скомпилировать несколько различных вариантов операторов 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

Ответы [ 2 ]

7 голосов
/ 10 декабря 2011

Да, похоже, что gcc выбрасывает "printf ("% s \ n ", buff)" и подставляет вместо него "put ()":

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 -педантичный 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
1 голос
/ 10 декабря 2011

Следующий ответ относится к 64-битному ассемблеру x86.

Краткий ответ: x86 не имеет% s в качестве какой-либо инструкции на ассемблере, то есть чистый c и даже java в наше время.

Длинный ответ:

  • Скомпилируйте вашу программу с символами (без зачистки): gcc -g yourprogram.c

  • Дамп сборки с смешанным c-кодом: objdump -S yourProgram.o

Следующий текст показывает, как strcpy и printf отображаются в сборке. Я также добавил, как вы должны читать сборку:

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