Пытаясь удалить ненужные вещи из моего связанного исполняемого файла, я обнаружил кое-что странное. Предположим, у нас есть простая и понятная программа на C++:
class Foo {
public:
template <typename T>
char* getPtr() {
static char c;
return &c;
}
};
char* bar() {
Foo i;
return i.getPtr<int>();
}
int main() {
bar();
}
Бинарный файл, создаваемый с помощью clang++ t.cc
, имеет следующую динамическую таблицу символов:
$ gobjdump -T ./a.out
./a.out: file format mach-o-x86-64
DYNAMIC SYMBOL TABLE:
0000000100000f40 g 0f SECT 01 0000 [.text] __Z3barv
0000000100000f60 g 0f SECT 01 0080 [.text] __ZN3Foo6getPtrIiEEPcv
0000000100001020 g 0f SECT 08 0080 [.data] __ZZN3Foo6getPtrIiEEPcvE1c
0000000100000000 g 0f SECT 01 0010 [.text] __mh_execute_header
0000000100000f80 g 0f SECT 01 0000 [.text] _main
0000000000000000 g 01 UND 00 0200 dyld_stub_binder
Учитывая, что это исполняемый файл, а не dylib, я хотел бы удалить все записи, кроме тех, которые содержат неопределенные символы. Теоретически двоичный файл все еще будет работать, поскольку информация о требуемой привязке dyld все еще существует, а точка входа определена в некоторой команде загрузки после заголовка mach-o (поэтому ничего общего с таблицей символов).
Попытка strip
дает странный результат:
$ strip ./a.out
$ gobjdump -T ./a.out
./a.out: file format mach-o-x86-64
DYNAMIC SYMBOL TABLE:
0000000005614542 d 3c OPT 00 0000 radr://5614542
0000000100000f60 g 0f SECT 01 0080 [.text] __ZN3Foo6getPtrIiEEPcv
0000000100001020 g 0f SECT 08 0080 [.data] __ZZN3Foo6getPtrIiEEPcvE1c
0000000100000000 g 0f SECT 01 0010 [.text] __mh_execute_header
0000000000000000 g 01 UND 00 0200 dyld_stub_binder
Последние две записи в любом случае не должны быть удалены, так как они требуются dyld для обработки этого исполняемого файла. При этом мы видим, что _main
и __Z3barv
уже нет. Но символы из class Foo
все еще там. Единственная разница между ними и раздетыми состоит в том, что у первых установлен флаг N_WEAK_DEF
(0080). Вот скудная информация от <mach-o/nlist.h>
об этом флаге:
/*
* The N_WEAK_DEF bit of the n_desc field indicates to the static and dynamic
* linkers that the symbol definition is weak, allowing a non-weak symbol to
* also be used which causes the weak definition to be discared. Currently this
* is only supported for symbols in coalesed sections.
*/
#define N_WEAK_DEF 0x0080 /* coalesed symbol is a weak definition */
К сожалению, это не объясняет, почему strip
игнорирует символы с этим флагом.
Итак, вопрос - как научить strip
удалять четные N_WEAK_DEF
символы, если пользователь просто не хочет их экспортировать.
P.S. Я просмотрел параметры команды и не нашел ничего полезного (-N
также удаляет неопределенные символы, поэтому это не вариант). Объявление этого класса с помощью visibility("hidden")
создает головоломку, но, к сожалению, это непросто сделать в реальном проекте.
MH_OBJECT
)? Обычно исполняемые файлы и общие библиотеки связываются с помощью ld64 с использованием формата байт-кода/сжатого перемещения, который dyld считывает при запуске, вместо перемещений на основе nlist, которые являются более информативными, но не используются в окончательных двоичных файлах, если это явно не запрошено. - person Kristina Brooks   schedule 30.08.2018LC_DYLD_INFO_ONLY
с информацией о перебазировании и связывании в обычном сжатом виде, но я не предоставил их, так как они не имеют отношения к моему вопросу. - person Sergio   schedule 30.08.2018