Я пытаюсь посчитать статические инициализаторы в файле C ++.
У меня уже есть решение (которое раньше работало с gcc-4.4), которое рассматривает размер ELF-секции .ctors.
После обновления до gcc-4.6 это, похоже, больше не возвращает действительных результатов (вычисленное количество статических инициализаторов равно 0, что не соответствует действительности, например, как возвращено nm).
Теперь проблема в том, что я бы хотел, чтобы решение работало даже в отсутствие символов (иначе я бы использовал nm).
Ниже приведен вывод readelf -SW примера исполняемого файла:
Существует 35 заголовков секций, начиная со смещения 0x4f39820:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00000174 000174 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 00000188 000188 000020 00 A 0 0 4
[ 3] .note.gnu.build-id NOTE 000001a8 0001a8 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 000001cc 0001cc 000918 04 A 5 0 4
[ 5] .dynsym DYNSYM 00000ae4 000ae4 00a5e0 10 A 6 1 4
[ 6] .dynstr STRTAB 0000b0c4 00b0c4 00ef72 00 A 0 0 1
[ 7] .gnu.version VERSYM 0001a036 01a036 0014bc 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 0001b4f4 01b4f4 000450 00 A 6 13 4
[ 9] .rel.dyn REL 0001b944 01b944 268480 08 A 5 0 4
[10] .rel.plt REL 00283dc4 283dc4 0048c8 08 A 5 12 4
[11] .init PROGBITS 0028868c 28868c 00002e 00 AX 0 0 4
[12] .plt PROGBITS 002886c0 2886c0 0091a0 04 AX 0 0 16
[13] .text PROGBITS 00291860 291860 3ac5638 00 AX 0 0 16
[14] malloc_hook PROGBITS 03d56ea0 3d56ea0 00075a 00 AX 0 0 16
[15] google_malloc PROGBITS 03d57600 3d57600 008997 00 AX 0 0 16
[16] .fini PROGBITS 03d5ff98 3d5ff98 00001a 00 AX 0 0 4
[17] .rodata PROGBITS 03d5ffc0 3d5ffc0 ffa640 00 A 0 0 64
[18] .eh_frame_hdr PROGBITS 04d5a600 4d5a600 0004b4 00 A 0 0 4
[19] .eh_frame PROGBITS 04d5aab4 4d5aab4 001cb8 00 A 0 0 4
[20] .gcc_except_table PROGBITS 04d5c76c 4d5c76c 0003ab 00 A 0 0 4
[21] .tbss NOBITS 04d5df0c 4d5cf0c 000014 00 WAT 0 0 4
[22] .init_array INIT_ARRAY 04d5df0c 4d5cf0c 000090 00 WA 0 0 4
[23] .ctors PROGBITS 04d5df9c 4d5cf9c 000008 00 WA 0 0 4
[24] .dtors PROGBITS 04d5dfa4 4d5cfa4 000008 00 WA 0 0 4
[25] .jcr PROGBITS 04d5dfac 4d5cfac 000004 00 WA 0 0 4
[26] .data.rel.ro PROGBITS 04d5dfc0 4d5cfc0 1b160c 00 WA 0 0 32
[27] .dynamic DYNAMIC 04f0f5cc 4f0e5cc 000220 08 WA 6 0 4
[28] .got PROGBITS 04f0f7ec 4f0e7ec 00a800 04 WA 0 0 4
[29] .data PROGBITS 04f1a000 4f19000 0206b8 00 WA 0 0 32
[30] .bss NOBITS 04f3a6c0 4f396b8 04c800 00 WA 0 0 32
[31] .comment PROGBITS 00000000 4f396b8 00002a 01 MS 0 0 1
[32] .shstrtab STRTAB 00000000 4f396e2 00013e 00 0 0 1
[33] .symtab SYMTAB 00000000 4f39d98 4ff960 10 34 140163 4
[34] .strtab STRTAB 00000000 54396f8 144992a 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
Должен ли я смотреть на .init или .init_array вместо этого? Не могли бы вы указать мне соответствующую документацию, которая объясняет изменение между версиями gcc или линкера?
Статические конструкторы могут быть вызваны любым из трех разделов .init
, .ctors
, или же .init_array
(от старейшего до новейшего в этом порядке). .init
содержит фрагмент кода, .ctors
а также .init_array
содержат указатели на код. Разница между .ctors
а также .init_array
имеет отношение к общему порядку выполнения конструкторов. Насколько я знаю, ничего из этого не задокументировано нигде, кроме комментариев к коду и сообщений в списке рассылки, но, вероятно, стоит проверить документы ELF ABI (g- и ps-оба).
Вы не могу вывести количество статических конструкторов в файле из размера любой из этих разделов. Допускается и обычно для компиляторов генерировать единственную специальную функцию, которая вызывает все конструкторы в файле и ссылается только на эту одну функцию в любом из разделов, которые она использует. Все, что вы можете знать наверняка (без изучения содержимого разделов, применения перемещений и указания указателей / инструкций вызова в .text
сегмент и обратный инжиниринг, что бы ни называлось) это: в объектном файле, если хотя бы один из этих разделов имеет ненулевой размер, то в файле имеется хотя бы один конструктор файловой или глобальной области видимости; если все три раздела пусты, то их нет. (В исполняемом файле все три раздела всегда непусты, поскольку определяемые ими структуры данных нуждаются в заголовках и трейлерах, которые автоматически добавляются во время соединения.)
Также обратите внимание, что конструкторы для статических объектов с блочной областью не вызывается из любого из этих разделов; они вызываются при первом достижении контроля их декларации.
Я предполагаю, что у вас есть доступ ко всему исходному коду ваших приложений (и, возможно, ко всем библиотекам, которые он называется). Это очевидно верно для свободного программного обеспечения.
Затем вы можете измерить это более точно во время компиляции, при компиляции (с последней версией GCC, например, 4.7 или 4.8) вашего приложения. Вы могли бы расширить это с ПЛАВИТЬСЯ (это высокоуровневый предметно-ориентированный язык для расширения GCC), или с болезненными плагинами GCC, написанными на C ++, для измерения таких вещей.
И я не совсем уверен, что ваш вопрос имеет точный смысл. Если ваша заявка, например, связан с некоторой разделяемой библиотекой, которая использует уловки видимости, чтобы скрыть свои статические конструкторы, понимая, сколько статических конструкторов, которые вызывает библиотека, на самом деле не определено.