Должны ли встроенные команды gcc всегда разрешаться на этапе компиляции или на этапе компоновщика?
При запуске gcc 3.4.3 в окне Solaris 5.11 я вижу, что встроенные функции остаются неопределенными во время компиляции, но разрешаются в libgcc.a, когда компоновщик Solaris ссылается на libgcc.a.
На gcc 4.5.2 на другом компьютере Solaris те же встроенные функции разрешаются во время компиляции.o, и компоновщик их не беспокоит.
Файл примера скомпилированного компилятора на gcc 3.4.3:
# cat ctzll.c
int func(unsigned long long x)
{
return __builtin_ctzll(x);
}
# cat main.c
int main(void)
{
return func(0xc0ffee);
}
Сначала скомпилируйте ctzll.c и проверьте символы:
# nm ctzll.o
U __ctzdi2
0000000000000000 T func
Теперь скомпилируйте main.c и свяжите объекты:
# gcc -m64 main.c -c
# gcc -m64 ctzll.o main.o -v
Reading specs from /usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/specs
Configured with: /build/i386/components/gcc3/gcc-3.4.3/configure --prefix=/usr/sfw --mandir=/usr/sfw/share/man --infodir=/usr/sfw/share/info --without-gnu-ld --with-ld=/usr/bin/ld --enable-languages=c,c++,f77,objc --enable-shared --with-gnu-as --with-as=/usr/gnu/bin/as
Thread model: posix
gcc version 3.4.3 (csl-sol210-3_4-20050802)
/usr/sfw/libexec/gcc/i386-pc-solaris2.11/3.4.3/collect2 -V -Y P,/lib/64:/usr/lib/64:/usr/sfw/lib/64 -R /lib/64:/usr/lib/64:/usr/sfw/lib/64 -Qy /usr/lib/amd64/crt1.o /usr/lib/amd64/crti.o /usr/lib/amd64/values-Xa.o /usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/amd64/crtbegin.o -L/usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/amd64 -L/usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/../../../amd64 -L/lib/amd64 -L/usr/lib/amd64 ctzll.o main.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh /usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/amd64/crtend.o /usr/lib/amd64/crtn.o
ld: Software Generation Utilities - Solaris Link Editors: 5.11-1.2276
# nm a.out | grep ctz
0000000000400fd0 T __ctzdi2
Итак, если я правильно понимаю, компоновщик Solaris разрешил __ctzdi2 (внутреннее представление __builtin_ctzll).
Теперь скомпилируйте gcc 4.5.2 на другом компьютере Solaris:
#gcc -m64 ctzll.c -c
# nm ctzll.o
0000000000000000 T func
Символ был точно разрешен в объектном файле, и он был встроен в сборку.o следующим образом:
8: 48 0f bc 45 f8 bsf -0x8(%rbp),%rax
Правильно ли работает компилятор 3.4.3? Я ожидал, что фактическая компиляция будет обрабатывать встроенные функции, такие как 4.5.2, ссылаясь на 64-битную версию libgcc.a. Отсутствие единообразия между компиляторами вызывает проблемы с исходным кодом в моем проекте, так как встроенный модуль остается неопределенным, а компоновщик не разрешает символы, так как я не связываюсь с конкретными 64-битными библиотеками ОС (libgcc.a). Я не уверен, что компилятор 3.4.3 неправильно настроен, что приводит к тому, что в файлах.o есть неопределенные встроенные функции, перехваченные связыванием, или если более новые компиляторы просто умнее, и мне нужно добавить 64-битные библиотеки в компоновщик для обработки старый компилятор
3.4.3, кажется, показывает действительный libgcc.a, который содержит определение _ctzdi2:
# gcc -m64 -print-libgcc-file-name
/usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/amd64/libgcc.a
# nm /usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/amd64/libgcc.a | grep ctzdi2
0000000000000000 T __ctzdi2
_ctzdi2.o:
1 ответ
Весь смысл libgcc.a заключается в реализации встроенных операций, для которых gcc не может генерировать код (который включает в себя не только функции __builtin_, но и такие вещи, как математические операции long long на некоторых 32-битных платформах).
Очевидно, что более новый gcc стал более умным в отношении выдачи кода.