2013-10-15 10 views
6

Когда я смотрю на символы в моей библиотеке, nm mylib.a, я вижу некоторые повторяющиеся записи, которые выглядят следующим образом:Что означает (.eh) в выходе nm?

000000000002d130 S __ZN7quadmat11SpAddLeavesC1EPNS_14BlockContainerEPy 
00000000000628a8 S __ZN7quadmat11SpAddLeavesC1EPNS_14BlockContainerEPy.eh 

Когда поступает через c++filt:

000000000002d130 S quadmat::SpAddLeaves::SpAddLeaves(quadmat::BlockContainer*, unsigned long long*) 
00000000000628a8 S quadmat::SpAddLeaves::SpAddLeaves(quadmat::BlockContainer*, unsigned long long*) (.eh) 

Что это .eh среднее и для чего этот дополнительный символ используется?

Я вижу, что это как-то связано с обработкой исключений. Но почему это использует дополнительный символ?

(я заметил это с лязгом)

+2

обработка исключений? –

+0

http://stackoverflow.com/a/5592898/1171191, также http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html – BoBTFish

+0

Итак, что-то делать с исключениями? В чем его цель? – Adam

ответ

4

Вот несколько простых код:

bool extenrnal_variable; 

int f(...) 
{ 
    if (extenrnal_variable) 
     throw 0; 

    return 42; 
} 

int g() 
{ 
    return f(1, 2, 3); 
} 

Я добавил extenrnal_variable, чтобы предотвратить компилятор от оптимизации всех ветвей прочь. f имеет ... для предотвращения вставки.

При компиляции с:

$ clang++ -S -O3 -m32 -o - eh.cpp | c++filt 

он испускает следующий код для g() (остальное опущено):

g():         ## @_Z1gv 
    .cfi_startproc 
## BB#0: 
    pushl %ebp 
Ltmp9: 
    .cfi_def_cfa_offset 8 
Ltmp10: 
    .cfi_offset %ebp, -8 
    movl %esp, %ebp 
Ltmp11: 
    .cfi_def_cfa_register %ebp 
    subl $24, %esp 
    movl $3, 8(%esp) 
    movl $2, 4(%esp) 
    movl $1, (%esp) 
    calll f(...) 
    movl $42, %eax 
    addl $24, %esp 
    popl %ebp 
    ret 
    .cfi_endproc 

Всех этих .cfi_* директив существуют для раскручивания стеки в случае исключение. Все они скомпилированы в блок FDE (запись описания кадра) и сохранены под именем g().eh (__Z1gv.eh). Эти директивы определяют, где в стеке регистры CPU сохраняются. Когда генерируется исключение, и стек разматывается, код в функции не должен выполняться (за исключением деструкторов локалей), но регистры, которые были сохранены ранее, должны быть восстановлены. Эти таблицы хранят именно эту информацию.

Эти таблицы могут быть сброшены с помощью инструмента dwarfdump:

$ dwarfdump --eh-frame --english eh.o | c++filt 

Выход:

0x00000018: FDE 
     length: 0x00000018 
    CIE_pointer: 0x00000000 
    start_addr: 0x00000000 f(...) 
    range_size: 0x0000004d (end_addr = 0x0000004d) 
    Instructions: 0x00000000: CFA=esp+4  eip=[esp] 
       0x00000001: CFA=esp+8  ebp=[esp] eip=[esp+4] 
       0x00000003: CFA=ebp+8  ebp=[ebp] eip=[ebp+4] 
       0x00000007: CFA=ebp+8  ebp=[ebp] esi=[ebp-4] eip=[ebp+4] 

0x00000034: FDE 
     length: 0x00000018 
    CIE_pointer: 0x00000000 
    start_addr: 0x00000050 g() 
    range_size: 0x0000002c (end_addr = 0x0000007c) 
    Instructions: 0x00000050: CFA=esp+4  eip=[esp] 
       0x00000051: CFA=esp+8  ebp=[esp] eip=[esp+4] 
       0x00000053: CFA=ebp+8  ebp=[ebp] eip=[ebp+4] 

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

Чтобы увидеть необработанный содержание этих символов вы можете перечислить все символы со своими сдвигами:

$ nm -n eh.o 

00000000 T __Z1fz 
     U __ZTIi 
     U ___cxa_allocate_exception 
     U ___cxa_throw 
00000050 T __Z1gv 
000000a8 s EH_frame0 
000000c0 S __Z1fz.eh 
000000dc S __Z1gv.eh 
000000f8 S _extenrnal_variable 

А потом сбросить (__TEXT,__eh_frame) раздел:

$ otool -s __TEXT __eh_frame eh.o 

eh.o: 
Contents of (__TEXT,__eh_frame) section 
000000a8 14 00 00 00 00 00 00 00 01 7a 52 00 01 7c 08 01 
000000b8 10 0c 05 04 88 01 00 00 18 00 00 00 1c 00 00 00 
000000c8 38 ff ff ff 4d 00 00 00 00 41 0e 08 84 02 42 0d 
000000d8 04 44 86 03 18 00 00 00 38 00 00 00 6c ff ff ff 
000000e8 2c 00 00 00 00 41 0e 08 84 02 42 0d 04 00 00 00 

Путем сопоставления корректоры вы могли видеть как кодируется каждый символ.

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

Дальнейшее чтение

2

Он выступает за стенды для обработчика исключений и, как правило, связан с ниже информацией:

Если вы используете список экспорта и строите либо общую библиотеку , или исполняемый файл, который будет использоваться с флагом ld -bundle_loader, вам необходимо включить символы для информации о кадре исключения в список экспорта для экспортированных символов C++. В противном случае они могут быть удалены. Эти символы заканчиваются на .eh; вы можете просмотреть их с помощью инструмента nm.

  • из XcodeUserGuide20
+0

Да, ссылки @ BoBTFish содержат этот параграф. Цель этого вопроса (и щедрости) заключается в том, чтобы объяснить, для чего предназначены эти символы .eh, чего этот абзац не делает. Например, каков символ информации о кадре исключения? Почему флаг -bundle_loader имеет значение? Этот параграф предполагает, что вы уже все это знаете. – Adam

+0

Извините, это означает обработчик исключений. У меня родился 2-летний новорожденный, и в последнее время это было немного беспокойно, поэтому я немного отвлекся, когда я собрал ответ. – JFelton

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

  • Нет связанных вопросов^_^