Как заставить слабую связь работать с GCC? - PullRequest
21 голосов
/ 08 ноября 2008

Похоже, есть 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. Что я делаю не так?

Ответы [ 5 ]

29 голосов
/ 20 сентября 2010

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

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

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

Вот е.с

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

Вот что whatnof.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
what, no f?

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

6 голосов
/ 08 апреля 2009

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

4 голосов
/ 08 ноября 2008

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

1 голос

Пример минимального запуска 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.

0 голосов
/ 08 ноября 2008

Из руководства по gcc doc:

слабый

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

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

...