Почему таблицы символов все еще существуют после компиляции - PullRequest
2 голосов
/ 19 марта 2020

Я понимаю, что таблицы символов создаются компилятором, чтобы помочь с его процессом. Они существуют для каждого объектного файла, когда они связаны друг с другом.

Предположим:

void test(void){
 //
}
void main(){
  return 0;
}

компиляция выше с g cc и запуск nm a.out показывает:

0000000100000fa0 T _main
0000000100000f90 T _test

Почему эти символы все еще необходимы? почему компоновщик не удаляет их после завершения? не являются ли они потенциально угрозой безопасности для хакеров при чтении источника?

Редактировать

Это то, что вы имеете в виду, отлаживая бинарный файл релиза (скомпилированный без -g)?

Предположим:

int test2(){
 int *p = (int*) 0x123;
 return *p;
}

int test1(){
 return test2();  
}

int main(){
 return test1();
}

, который вызывает ошибку по test2. gdb ./a.out> where показывает:

(gdb) where
#0  0x000055555555460a in test2 ()
#1  0x000055555555461c in test1 ()
#2  0x000055555555462c in main ()

Но снимает a.out и делает то же самое:

(gdb) where
#0  0x000055555555460a in ?? ()
#1  0x000055555555461c in ?? ()
#2  0x000055555555462c in ?? ()

Это то, что вы подразумеваете под keeping symbol tables for debugging release builds? это нормальный способ сделать это? другие инструменты используются?

1 Ответ

1 голос
/ 19 марта 2020

Почему эти символы все еще нужны?

Они не нужны для правильности выполнения, но они полезны для отладки.

Некоторые программы могут записывать свои собственные трассировка стека (например, TCMalloc выполняет выборку распределения) и сообщает об этом в cra sh (или других видах ошибок).

Хотя все такие трассировки стека могут быть символизированы в автономном режиме (учитывая двоичный код, который содержит содержит символы), часто программе гораздо удобнее производить символизированную трассировку стека, поэтому не требуется для поиска подходящего двоичного файла.

Рассмотрим случай, когда у вас есть тысячи различных приложений, работающих в облаке в нескольких версиях, и вы получите 100 отчетов о краже sh. Это одни и те же крэ sh, или есть разные причины?

Если все, что у вас есть, это сгустки шестнадцатеричных чисел, сказать сложно. Вам нужно будет найти соответствующий двоичный файл для каждого экземпляра, символизировать его и сравнить со всеми остальными (здесь может помочь автоматизация).

Но если у вас есть трассировки стека в символизированной форме, это довольно легко Краткий обзор.

Это немного затратно: ваши двоичные файлы, возможно, на 1% больше, чем должны быть.

почему компоновщик не работает удалить их когда-нибудь?

Вы должны помнить традиционные UNIX корни. В среде, в которой разрабатывался UNIX, каждый имел доступ к источнику для всех утилит UNIX (включая ld), и отладка была гораздо важнее, чем сохранение секретности. Поэтому я нисколько не удивлен, что выбрано это значение по умолчанию (сохранить символы).

Сравните с выбором, сделанным Microsoft - сохраните все в .DBG (позже .PDB файлы).

не являются ли они потенциально угрозой безопасности для хакеров при чтении источника?

Они полезны в обратном инжиниринге, да. Они не содержат источника, поэтому, если источник уже не открыт, они не добавляют , что много.

Тем не менее, если ваша программа содержит что-то вроде CheckLicense(), это помогает хакерам сконцентрировать свои усилия на обходе ваших лицензионных проверок.

Именно поэтому коммерческие двоичные файлы часто поставляются полностью раздетыми.

Обновление:

Это то, что вы имеете в виду, сохраняя таблицы символов для отладки сборок релиза?

Да.

это нормальный способ сделать это ?

Это один из способов сделать это.

используются ли другие инструменты?

Да: см. Лучшие практики ниже.

PS Лучше всего собирать двоичные файлы с помощью full отладочной информации:

gcc -c -g -O2 foo.c bar.c
gcc -g -o app.dbg foo.o bar.o ...

Затем сохраняйте полный двоичный файл отладки app.dbg для случаев, когда вам нужно отлаживать сбои, но отправим полностью разорванную версию app своим клиентам:

strip app.dbg -o app

PPS

g cc -g is us Ред для GDB. g cc без -g по-прежнему имеет таблицы символов.

Рано или поздно вы обнаружите, что должен выполнить отладку в двоичном файле, который построен без -g (например, когда двоичный файл, созданный без -g, аварийно завершает работу, а другой, созданный с -g - нет).

Когда наступит этот момент, ваша работа будет значительной проще, если в двоичном файле еще есть таблица символов.

...