[devel] libc on i586: WTF?

Sergey Vlasov vsu на altlinux.ru
Сб Окт 16 11:40:16 UTC 2010


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 не нужна.
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя     : отсутствует
Тип     : application/pgp-signature
Размер  : 198 байтов
Описание: Digital signature
Url     : <http://lists.altlinux.org/pipermail/devel/attachments/20101016/07b273c0/attachment.bin>


Подробная информация о списке рассылки Devel