On Sat, Oct 16, 2010 at 12:26:18PM +0800, REAL wrote: > Что-то загадочное произошло на вчерашнем срезе сизифа (может быть и > раньше так было, только не замечал): > > $ gfortran -O2 -c ilaenv.f > $ nm ilaenv.o|grep stack_chk_fail > U __stack_chk_fail > > НО: > $ gfortran -fPIC -O2 -c ilaenv.f > $ nm ilaenv.o|grep stack_chk_fail > U __stack_chk_fail_local > > Проявляется на i586, на x86_64 всё в порядке. На самом деле так было уже очень давно. > Символ __stack_chk_fail_local присутствует только в libc.a, не в libc.so: Ещё он присутствует в libc_nonshared.a, при этом файл libc.so, используемый при компоновке, на самом деле представляет собой ld script: /* GNU ld script Use the shared library, but some functions are only in the static library, so try that secondarily. */ OUTPUT_FORMAT(elf32-i386) GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux.so.2 ) ) Т.е., в каждый исполняемый файл или разделяемую библиотеку попадает собственная копия необходимых функций из libc_nonshared.a. Функция __stack_chk_fail_local на самом деле просто вызывает функцию __stack_chk_fail из libc.so.6. Эта промежуточная функция, локальная для разделяемой библиотеки, добавлена с целью оптимизации. Дело в том, что вызов функции __stack_chk_fail из другого модуля должен производиться через PLT, для чего i386 ELF ABI требует перед вызовом загрузить в регистр %ebx указатель на GOT; вызов же локальной для модуля функции __stack_chk_fail_local может производиться напрямую и не требует предварительной инициализации %ebx, а уже в реализации __stack_chk_fail_local в одном экземпляре на каждый модуль присутствует код, устанавливающий требуемое значение %ebx перед вызовом __stack_chk_fail через PLT. В системе команд x86_64, в отличие от i386, есть возможность адресации данных по смещению от адреса текущей команды (%rip), поэтому не требуется занимать отдельный регистр для хранения адреса GOT, и вызов функции через PLT не требует предварительной подготовки, поэтому там функция __stack_chk_fail просто вызывается напрямую, и локальная для модуля функция __stack_chk_fail_local не нужна.