2009-08-06 2 views
50

Я пытаюсь разобрать программу, чтобы увидеть инструкцию сборки syscall (инструкция INT, я полагаю), и обработчик с GDB и написал небольшую программу (см. Ниже) для нее, которая открывает и закрывает файл. Я смог выполнить вызов, чтобы открыть с GDB, пока он не выполнит вызов. Когда я попытался рассказать GDB «разобрать 0x ....» (адрес вызова), он ответил «Нет функции содержит указанный адрес». Можно ли заставить GDB разобрать (или как можно лучше отобразить его на ассемблере) адрес памяти? Если да, то как?Как заставить GDB разбирать?

#include <stdio.h> 
#include <stdlib.h> 

int main() { 
    FILE* f; 
    f = fopen("main.c", "r"); 
    if (!f) { 
     perror("open"); 
     return -1; 
    } 
fclose(f); 
return 0; 
} 
+2

fopen() не является системным вызовом, это вызов стандартной библиотеки C. И почему, по вашему мнению, системный вызов должен выполняться с помощью инструкции INT? – 2009-08-07 16:25:51

+0

Возможно, я ошибаюсь, но нас учили, что вызовы fopen в конечном итоге приводят к системному вызову ядра, чтобы открыть файл и вернуть дескриптор файла? – Patrick

+1

Патрик: Да, но не нужно это делать. Обычно он вызывает функцию libc, которая затем входит в ядро. Но вызов ядра может выполняться не только с помощью int (это медленно), но с syscall/sysenter в зависимости от архитектуры процессора ... – k3a

ответ

40

Вы хотите только разобрать свой основной? Если это так, попробуйте следующее:

(gdb) info line main 
(gdb) disas STARTADDRESS ENDADDRESS 

Как так:

[email protected] /cygdrive/c/prog/dsa 
$ gcc-3.exe -g main.c 

[email protected] /cygdrive/c/prog/dsa 
$ gdb a.exe 
GNU gdb 6.8.0.20080328-cvs (cygwin-special) 
... 
(gdb) info line main 
Line 3 of "main.c" starts at address 0x401050 <main> and ends at 0x401075 <main+ 
(gdb) disas 0x401050 0x401075 
Dump of assembler code from 0x401050 to 0x401075: 
0x00401050 <main+0>: push %ebp 
0x00401051 <main+1>: mov %esp,%ebp 
0x00401053 <main+3>: sub $0x18,%esp 
0x00401056 <main+6>: and $0xfffffff0,%esp 
0x00401059 <main+9>: mov $0x0,%eax 
0x0040105e <main+14>: add $0xf,%eax 
0x00401061 <main+17>: add $0xf,%eax 
0x00401064 <main+20>: shr $0x4,%eax 
0x00401067 <main+23>: shl $0x4,%eax 
0x0040106a <main+26>: mov %eax,-0xc(%ebp) 
0x0040106d <main+29>: mov -0xc(%ebp),%eax 
0x00401070 <main+32>: call 0x4010c4 <_alloca> 
End of assembler dump. 

Я не вижу ваш вызов прерывания системы, однако. (это было некоторое время с тех пор, как я в последний раз пытался сделать системный вызов в сборке. INT 21h, хотя, последний раз я помню

+0

ОК, тогда я буду искать INT 21h в будущем. Спасибо за этот намек. Но то, что я хотел попробовать, это следовать последовательности вызовов, происходящей из fopen() (не видеть ее в вашем коде ...) «вниз», пока не увижу команду INT. – Patrick

+1

Управляется им - путь к использованию - это как ваш ответ, так и Фалаина. Мне пришлось скомпилировать его статически с помощью gcc --static main.c, а затем использовать gdb/objdump, чтобы углубиться в библиотеку C. В конечном итоге это привело к вызову __open_nocancel, который сделал * INT 0x80 *. Спасибо вам обоим – Patrick

+4

Примечание: синтаксис 'disas 0x401050 0x401075' по крайней мере в версии gdb 7.7 не будет работать. Вы скорее пишете его как 'disas 0x401050,0x401075'. Кроме того, возможно, вы захотите добавить префикс «/ m», чтобы показать исходный код: 'disas \ m 0x401050,0x401075' –

28

Это не прямой ответ на ваш вопрос, но поскольку вы, похоже, просто хотите разобрать двоичный файл , возможно, вы могли бы просто использовать objdump:

objdump -d program 

Это должно дать вам его dissassembly вы можете добавить -S если вы хотите его источник аннотированный

+0

⁺¹ для '-S', я не знал, что он может включать исходный код. –

6

вы можете заставить куб.см до выхода непосредственно на ассемблере путем добавления.. -S переключатель

gcc -S hello.c 
83

Да, разборки не самая лучшая команда для использования здесь. Команда вы хотите «х/я» (рассматривать в качестве инструкции):

(gdb) x/i 0xdeadbeef 
+3

СПАСИБО! Добавление этого текста, чтобы помочь другим найти этот намек: это инструкция, которая будет использоваться для разборки двоичного блоба, дизассемблирования ПЗУ, изучения инструкции в двоичном файле изображения и т. Д. Запишите небольшую программу C, чтобы fread() двоичный блок в буфер. Затем сделайте 'x/i' в буфере. – user188012

+0

@ user188012, если вы хотите разобрать двоичный блок, более простой способ сделать это - использовать отдельный дизассемблер, такой как ndisasm или аналогичный. –

+0

Вы можете использовать: x/i $ pc, чтобы получить инструкцию для ПК, которая является адресом текущей инструкции. – k3a

3

Если все, что вы хотите, чтобы увидеть разборку с вызовом INTC, используйте objdump -d, как кто-то упомянул, но использовать - статическая опция при компиляции. В противном случае функция fopen не будет скомпилирована в эльф и связана во время выполнения.

7

fopen() - это функция библиотеки C, поэтому вы не увидите никаких команд syscall в своем коде, а просто обычный вызов функции. В какой-то момент он вызывает open (2), но он делает это через батут. Существует просто переход на страницу VDSO, которая предоставляется ядром для каждого процесса. Затем VDSO предоставляет код для вызова системы. На современных процессорах будут использоваться команды SYSCALL или SYSENTER, но вы также можете использовать INT 80h на процессорах x86.

1

Вам не нужно использовать gdb. GCC это сделает.

gcc -S foo.c 

Это создаст foo.s, который является сборкой.

gcc -m32 -c -g -Wa,-a,-ad foo.c > foo.lst 

В приведенной выше версии будет создан файл списка, в котором есть как C, так и сборка, сгенерированная им. GCC FAQ

1

gdb disassemble имеет a/m для включения исходного кода вместе с инструкциями. Это эквивалентно objdump -S, с дополнительным преимуществом, ограничивающим только одну функцию (или адрес-диапазон), представляющую интерес.

Смежные вопросы