Отладка среды выполнения C - PullRequest
3 голосов
/ 02 ноября 2011

Я хочу получить подробный обзор того, что происходит до и после main() с использованием GDB. Достаточно ли будет просто перекомпилировать glibc с -g и ссылаться на него?

Ответы [ 2 ]

4 голосов
/ 02 ноября 2011

Вам не нужно запускаться в отладчике.

Когда ОС загружает ваш исполняемый файл, она передает управление своей точке входа, которая не является функцией с именем main().В GCC и glibc истинная точка входа обычно называется _start, но ваш пробег может варьироваться в зависимости от вашей платформы.Конечно, если вы не используете glibc или используете другой компилятор C, он может отличаться еще больше.

Основная задача кода на _start состоит в инициализации всего, что требуетсячтобы создать условия, которые main() ожидает.Обратите внимание, что это на намного сложнее для C ++, и, поскольку GCC поддерживает оба языка, истинный код запуска будет иметь дополнительные функции, единственная цель которых - поддерживать требования C ++.

Исходный коддля _start почти всегда написано на ассемблере, и это сильно зависит от платформы.Для 32-битной платформы x86 один образец можно найти в дереве исходных текстов glibc в разделе sysdeps/i386/elf/start.S.

Хотя вполне вероятно, что вам никогда не понадобится это видеть, чтобыдля отладки обычного кода в настольных операционных системах при работе на небольших встроенных системах часто требуется хорошее понимание инициализации среды выполнения.В частности, многие встроенные системы загружаются непосредственно из сброса системы в версию этого кода запуска.В такой системе нет ничего необычного в том, чтобы включать память, которая будет использоваться, или правильно настраивать основные тактовые источники ЦП и устанавливать указатель первого стека на что-то разумное, прежде чем можно будет беспокоиться о концепциях более высокого уровня, таких какСегменты .text, .data и .bss.

Версия start.S, связанная с, предполагает, что она запускается под некой разновидностью Unix или Linux (я не выглядел слишком внимательно).Таким образом, можно предположить, что процесс создан и что сегменты кода и данных уже загружены и готовы к использованию.Он преобразует параметры командной строки из формата, предоставленного ОС, в привычные arvc и argv[], необходимые для вызова main(), что он делает, но через оболочку, предоставленную где-то еще в источниках glibc с именем __libc_start_main(), найденных вcsu/libc-start.c.

Источник этой функции выглядит чрезвычайно сложным из-за обилия директив компиляции условий, которые поддерживают широкий спектр функций.Но по сути это сводится к следующему для общего случая:

STATIC int
__libc_start_main(int (*main) (int, char **, char **),
                 int argc, char **av,
                 int (*init)(int, char **, char **),
                 void (*fini) (void),
                 void (*rtld_fini) (void), void *__unbounded stack_end)
{

    int result;
    /* some basic initializations goes here, then... */
    /* initialize some core parts of the library */
    __libc_init_first (argc, argv, __environ);
    /* arrange to call finalizers at exit if any */
    if (fini)
        __cxa_atexit ((void (*) (void *)) fini, NULL, NULL);
    /* call initializers, if any */
    if (init)
        init(argc, argv, __environ);
    /* call user's actual main, which might not return */
    result = main (argc, argv, __environ);
    /* if main did return, exit appropriately */
    exit (result);
}

В этом наброске я пропустил некоторые детали, но в общих чертах это должно быть верно.Забавный бизнес с указателями на функции init и fini в первую очередь заключается в поддержке конструкторов и деструкторов глобальных объектов в программе на C ++.Для простой связи C эти указатели будут иметь значение NULL, и никакого эффекта не будет.

3 голосов
/ 02 ноября 2011

Если вы хотите поиграть с отладчиком, вы можете использовать GDB следующим образом:

  • установить отладочную информацию для пакета `glibc` ( здесь - это способчтобы сделать это с Fedora, я не знаю о других дистрибутивах)
  • или указать GDB на согласованный каталог файлов отладки:
(gdb) show debug-file-directory
The directory where separate debug symbols are searched for is "/usr/lib/debug".
(gdb) set debug-file-directory ...

(это /usr/lib/debug/lib64/libc-2.14.so.debug вмоя система)

  • скажите GDB показать обратный след перед вашим `main`:
(gdb) show backtrace past-entry
Whether backtraces should continue past the entry point of a program is off.
(gdb) set backtrace past-entry on
  • тогда вы должны увидеть то, что ищете,и перемещаться по нему:
(gdb) where
#0  main () at test.c:4
#1  __libc_start_main (main=0x40050f <main>, argc=1,...) at libc-start.c:226
#2  _start ()
...