Как заставить слабое связывание работать с GCC?

Кажется, есть 3 способа сообщить GCC о слабой ссылке символа:

  • __attribute__((weak_import))
  • __attribute__((weak))
  • #pragma weak symbol_name

Ни один из них не работает для меня:

#pragma weak asdf
extern void asdf(void) __attribute__((weak_import, weak));
...
{
    if(asdf != NULL) asdf();
}

Я всегда получаю ошибку ссылки, как это:

Undefined symbols:
  "_asdf", referenced from:
      _asdf$non_lazy_ptr in ccFA05kN.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

Я использую GCC 4.0.1 на OS X 10.5.5. Что я делаю неправильно?


person Community    schedule 08.11.2008    source источник
comment
int __attribute__((weak)) main() { ... } у меня отлично работает с gcc/Mac OS X, но не компилируется с gcc/MinGW. :(   -  person mcandre    schedule 13.09.2012


Ответы (5)


Я только что изучил это и подумал, что некоторые другие могут быть заинтересованы в моих выводах.

Слабое связывание с weak_import действительно хорошо работает только с динамическими библиотеками. Вы можете заставить его работать со статической компоновкой (указав -undefined dynamic_lookup, как было предложено выше), но это не такая уж горячая идея. Это означает, что неопределенные символы не будут обнаружены до времени выполнения. Это то, чего я бы лично избегал в производственном коде.

Вот сеанс терминала Mac OS X, показывающий, как заставить его работать:

Вот ф.к.

int f(int n)
{
    return n * 7;
}

Вот что.c

#include <stdio.h>
#include <stdlib.h>

extern int f (int) __attribute__((weak_import));

int main() {
    if(f == NULL)
        printf("what, no f?\n");
    else
        printf("f(8) is %d\n", f(8));
    exit(0);
}

Сделать динамическую библиотеку из f.c:

$ cc -dynamiclib -o f.dylib f.c

Скомпилируйте и свяжите с динамической библиотекой, перечислите динамические библиотеки.

$ cc -o whatnof whatnof.c f.dylib
$ otool -L whatnof
whatnof:
       f.dylib (compatibility version 0.0.0, current version 0.0.0)
       /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.0)

Запустите whatnof, чтобы посмотреть, что произойдет:

$ whatnof
f(8) is 56

Теперь замените f.dylib пустой библиотекой (без символов):

$ mv f.dylib f.dylib.real
$ touch null.c
$ cc -dynamiclib -o f.dylib null.c

Запустите тот же whatnof, чтобы увидеть, что произойдет:

$ whatnof
what, no f?

Основная идея (или «вариант использования») для weak_import заключается в том, что он позволяет вам связываться с набором динамических (общих) библиотек, а затем запускать тот же код с более ранними версиями тех же библиотек. Вы можете проверить функции на NULL, чтобы узнать, поддерживаются ли они в конкретной динамической библиотеке, с которой в данный момент выполняется код. Кажется, это часть базовой модели разработки, поддерживаемой Xcode. Я надеюсь, что этот пример будет полезен; это помогло мне успокоиться об этой части дизайна Xcode.

person Community    schedule 20.09.2010

Добавьте -Wl,-flat_namespace,-undefined,dynamic_lookup в строку компилятора gcc, которую вы используете для окончательной ссылки.

person Community    schedule 08.04.2009
comment
Когда я использую gcc/MinGW, он говорит cc1.exe: error: unrecognized command line option "-flat_namespace,-undefined,dynamic_lookup". - person mcandre; 13.09.2012

Вам необходимо установить для переменной MACOSX_DEPLOYMENT_TARGET значение 10.2 или более поздней версии. См. документацию Apple и их техническая заметка о слабых связях.

person Community    schedule 08.11.2008
comment
Я видел это, и это установлено таким образом. Это не та ошибка, которую я получаю. - person ; 08.11.2008

Пример Linux с минимальной работоспособностью

main.c

#include <stdio.h>

int my_weak_var __attribute__((weak)) = 1;

int main(void) {
    printf("%d\n", my_weak_var);
}

notmain.c

int my_weak_var = 2;

Скомпилируйте и запустите оба объекта:

gcc -c -std=c99 -Wall -Wextra -pedantic -o main.o main.c
gcc -c -std=c99 -Wall -Wextra -pedantic -o notmain.o notmain.c
gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.o notmain.o
./main.out

Вывод:

2

Скомпилируйте и запустите без notmain.o:

gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.o
./main.out

Вывод:

1

GitHub upstream.

Итак, мы видим, что если задано notmain.o, то неслабый символ имеет приоритет, как и ожидалось.

Мы можем проанализировать Объектный файл ELF с символами:

nm main.o notmain.o

который дает:

main.o:
                 U _GLOBAL_OFFSET_TABLE_
0000000000000000 T main
0000000000000000 V my_weak_var
                 U printf

notmain.o:
0000000000000000 D my_weak_var

а потом:

man nm

содержит:

Тип символа. По крайней мере, используются следующие типы; другие также зависят от формата объектного файла. В нижнем регистре символ обычно является локальным; если в верхнем регистре, символ является глобальным (внешним). Однако есть несколько символов нижнего регистра, которые показаны для специальных глобальных символов («u», «v» и «w»).

"D"
"d" Символ находится в разделе инициализированных данных.

"V"
"v" Символ является слабым объектом. Когда слабо определенный символ связан с нормально определенным символом, нормально определенный символ используется без ошибок. Когда слабый неопределенный символ связан и символ не определен, значение слабого символа становится равным нулю без ошибки. В некоторых системах прописные буквы означают, что задано значение по умолчанию.

Однако при работе со статическими библиотеками .a вам, возможно, придется использовать -Wl,--whole-archive, как описано по адресу: Как сделать так, чтобы сильный символ ссылки gcc в статической библиотеке перезаписывал слабый символ?

Слабые символы также можно оставить неопределенными, что в Binutils приводит к «зависимому от платформы поведению», см.: Поведение GCC для неразрешенных слабых функций

Протестировано на Ubuntu 18.10, GCC 8.2.0.

person Community    schedule 08.02.2019

Из руководства по документации gcc:

слабый

Слабый атрибут приводит к тому, что объявление выдается как слабый символ, а не как глобальный. Это в первую очередь полезно при определении библиотечных функций, которые можно переопределить в пользовательском коде, хотя его также можно использовать с объявлениями, не являющимися функциями. Слабые символы поддерживаются для целей ELF, а также для целей a.out при использовании ассемблера и компоновщика GNU.

это означает, что объект может перезаписывать слабый символ (определенный в другом объекте/библиотеке) без возникновения ошибок во время компоновки. Неясно, связываете ли вы библиотеку с символом weak или нет. Похоже, что вы не определили символ, и библиотека не подключена должным образом.

person Community    schedule 08.11.2008
comment
Похоже, что слабое связывание можно использовать двумя способами: gcc.gnu.org/ ml/gcc/1999-02n/msg01219.html Я пытаюсь создать ссылку на старую версию библиотеки. Текущая версия определяет функции, которых не было в старой. Я хочу иметь возможность использовать новые функции, если они доступны во время выполнения. - person ; 08.11.2008
comment
Эта цитата здесь не применима: дизайн слабых ссылок Mac OS X [взят из классического диспетчера фрагментов кода Mac OS]. Если вы знакомы с [ELF], возможно, вы привыкли к другому значению терминов слабый символ или слабая связь, где слабый символ может быть заменен неслабым символом. символ. Эквивалентной функцией Mac OS X является слабое определение — см. "Область действия и обработка определений символов" для получения дополнительной информации. - person Jeremy W. Sherman; 06.12.2010
comment
Согласен: документация Apple неточно описывает gcc. Справедливо, учитывая, что gcc изначально неправильно описывает себя. - person MarcH; 05.10.2018