__attribute__ ((слабый)) не работает для глобальной переменной - PullRequest
0 голосов
/ 31 января 2019
pqy@localhost ~/src/test/a $ cat m.c
#include <stdio.h>
int aaaaa __attribute__ ((weak)) =8;
int main(void){
    printf("%d\n", aaaaa);
    return 0;
}
pqy@localhost ~/src/test/a $ cat lib.c
int aaaaa = 5;

pqy@localhost ~/src/test/a $ gcc lib.c -fPIC -shared -o libb.so;gcc m.c -o m -L. -lb -Wl,-rpath=$PWD;./m
8

Выше мой код и результат теста.Я запутался, почему это не работает, как ожидалось.

Также попробуйте функцию, а не работать эфир.Ниже приведен результат теста.

pqy@localhost ~/src/test/a $ cat lib.c
int fun() {
    return 5;
}
pqy@localhost ~/src/test/a $ cat m.c
#include <stdio.h>
__attribute__((weak)) int fun() {
    return 8;
}
int main(void){
    printf("%d\n", fun());
    return 0;
}
pqy@localhost ~/src/test/a $ gcc lib.c -fPIC -shared -o libb.so;gcc m.c -O0 -o m -L. -lb -Wl,-rpath=$PWD;./m
8
pqy@localhost ~/src/test/a $ ldd m
        linux-vdso.so.1 (0x00007ffd819ec000)
        libb.so => /home/pqy/src/test/a/libb.so (0x00007f7226738000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f7226533000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f7226744000)
pqy@localhost ~/src/test/a $

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

В сущности, вы заметили, что компоновщик не может разрешить символ динамически, если он может разрешить его статически.См .:

main.c

extern void foo(void);
extern void need_dynamic_foo(void);
extern void need_static_foo(void);

int main(void){
    foo();
    need_dynamic_foo();
    need_static_foo();
    return 0;
}

dynamic_foo.c

#include <stdio.h>

void foo(void)
{
    puts("foo (dynamic)");
}

void need_dynamic_foo(void)
{
    puts(__func__);
}

static_foo.c

#include <stdio.h>

void foo(void)
{
    puts("foo (static)");
}

void need_static_foo(void)
{
    puts(__func__);
}

Скомпилируйте исходники так:

$ gcc -Wall -c main.c static_foo.c
$ gcc -Wall -fPIC -c dynamic_foo.c

Создайте общую библиотеку:

$ gcc -shared -o libfoo.so dynamic_foo.o

И свяжите программу:

$ gcc -o prog main.o static_foo.o libfoo.so -Wl,-rpath=$PWD

Он работает так:

$ ./prog
foo (static)
need_dynamic_foo
need_static_foo

Так что foo и need_static_foo были статически разрешены к определениям из static_foo.o, а определение foo из libfoo.so было проигнорировано, несмотря натот факт, что libfoo.so был , необходим и дал определение need_dynamic_foo.Не имеет значения, если мы изменим порядок связи на:

$ gcc -o prog main.o libfoo.so static_foo.o -Wl,-rpath=$PWD
$ ./prog
foo (static)
need_dynamic_foo
need_static_foo

Также не имеет значения, если мы заменим static_foo.c на:

static_weak_foo.c

#include <stdio.h>

void __attribute__((weak)) foo(void)
{
    puts("foo (static weak)");
}

void need_static_foo(void)
{
    puts(__func__);
}

Скомпилируйте это и выполните повторную ссылку:

$ gcc -Wall -c static_weak_foo.c
$ gcc -o prog main.o libfoo.so static_weak_foo.o -Wl,-rpath=$PWD
$ ./prog
foo (static weak)
need_dynamic_foo
need_static_foo

Хотя определение foo в static_weak_foo.c теперь объявлено слабым, тот факт, что foo может быть статически разрешенным к этому определению по-прежнему исключает необходимость его динамического разрешения.

Теперь, если мы напишем другой исходный файл, содержащий другое строгое определение foo:

static_strong_foo.c

#include <stdio.h>

void foo(void)
{
    puts("foo (static strong)");
}

и скомпилируйте его и сделайте ссылку следующим образом:

$ gcc -Wall -c static_strong_foo.c
$ gcc -o prog main.o static_weak_foo.o libfoo.so static_strong_foo.o -Wl,-rpath=$PWD

мы видим:

$ ./prog
foo (static strong)
need_dynamic_foo
need_static_foo

Теперь libfoo.so все еще дает определениеneed_dynamic_foo, потому что другого нет;static_weak_foo.o по-прежнему предоставляет единственное определение need_static_foo, а определение foo в libfoo.so по-прежнему игнорируется, поскольку символ может быть разрешен статически.

Но в этом случае есть два определенияfoo в разных файлах, которые доступны для статического разрешения: слабое определение в static_weak_foo.o и строгое определение в static_strong_foo.o.По правилам связывания, с которыми вы знакомы, побеждает сильное определение.

Если бы оба эти статически связанных определения foo были сильными, то, конечно, была бы ошибка множественного определения, например:

$ gcc -o prog main.o static_foo.o libfoo.so static_strong_foo.o -Wl,-rpath=$PWD
static_strong_foo.o: In function `foo':
static_strong_foo.c:(.text+0x0): multiple definition of `foo'
static_foo.o:static_foo.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status

, в котором динамическое определение в libfoo.so не играет роли .Таким образом, вы можете руководствоваться этим практическим принципом: правила, с которыми вы знакомы для арбитража между слабыми и сильными определениями одного и того же символа в связи, применяются только к конкурирующим определениям , которые могут вызвать ошибку множественного определения в отсутствие weak атрибут .

0 голосов
/ 31 января 2019

Символ разрешается на этапе соединения, на этапе соединения виден только слабый символ aaaaa = 8.

Если символ можно разрешить на этапе соединения, он не будет генерировать запись перемещения, тогда на этапе загрузки ничего не произойдет

В таблице перемещения нет aaaaa:

% objdump -R m         

m:     file format elf64-x86-64

DYNAMIC RELOCATION RECORDS
OFFSET           TYPE              VALUE 
0000000000003dc8 R_X86_64_RELATIVE  *ABS*+0x0000000000001130
0000000000003dd0 R_X86_64_RELATIVE  *ABS*+0x00000000000010f0
0000000000004028 R_X86_64_RELATIVE  *ABS*+0x0000000000004028
0000000000003fd8 R_X86_64_GLOB_DAT  _ITM_deregisterTMCloneTable
0000000000003fe0 R_X86_64_GLOB_DAT  __libc_start_main@GLIBC_2.2.5
0000000000003fe8 R_X86_64_GLOB_DAT  __gmon_start__
0000000000003ff0 R_X86_64_GLOB_DAT  _ITM_registerTMCloneTable
0000000000003ff8 R_X86_64_GLOB_DAT  __cxa_finalize@GLIBC_2.2.5
0000000000004018 R_X86_64_JUMP_SLOT  printf@GLIBC_2.2.5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...