Глобальные переменные, общие библиотеки и эффект -fPIC - PullRequest
13 голосов
/ 04 сентября 2011

Я создал фрагмент кода, который состоит из динамической библиотеки (lib.c) и основного исполняемого файла (main.c).В обоих файлах я определяю глобальную переменную с именем: int global.Не очень умный, но это не вопрос.

Когда я компилирую динамическую библиотеку, опция -fPIC кажется обязательной:

gcc lib.c -fPIC -shared -o lib.so

в противном случае я получаю:

/usr/bin/ld: /tmp/ccpUvIPj.o: relocation R_X86_64_32 against '.rodata' can not be used when making a shared object; recompile with -fPIC

Когда я компилирую исполняемый файл, это не так.

gcc main.c -fPIC -ldl
gcc main.c -ldl

Оба работают, но имеют разное поведение, которое я не могу объяснить, не так ли?:

с -fPIC, global в main.c и global в lib.c - это одни и те же переменные:

global main: 23 (0x601050)
global lib: 23 (0x601050)

без -fPIC, global в lib.c не коррелирует с globalв main.c:

global main: 23 (0x601048)
global lib: 0 (0x7f7742e64028)

Вот источник:

lib.c

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

int global;

int f_one() {

    printf("global lib: %d (%p)\n", global, &global);

    return EXIT_SUCCESS;
}

main.c

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

void * handle;
int global;

int main() {

    int q = 7;

    int (* f_one_p)(int a) = NULL;

    global = 23;

    handle = dlopen("./lib.so", RTLD_NOW);

    if (handle == 0) {
        return EXIT_FAILURE;
    }

    f_one_p = dlsym(handle, "f_one");

    printf("global main: %d (%p)\n", global, &global);

    f_one_p(q);

    return EXIT_SUCCESS;

}

gcc--version: gcc (Ubuntu / Linaro 4.5.2-8ubuntu4) 4.5.2

uname -a: Linux xxx 2.6.38-11-generic # 48-Ubuntu SMP пт 29 июля 19:02:55UTC 2011 x86_64 x86_64 x86_64 GNU / Linux

edit : код, протестированный в архитектурах SUN / sparc и x86 / Linux с такими же неожиданными общими глобальными переменными (с -fPIC).

Ответы [ 2 ]

8 голосов
/ 04 сентября 2011

Когда вы компилируете с -fPIC, рассматриваемый объект будет определять адрес глобальных символов, используя Global Offset Table . Что происходит, хотя, когда часть кода -fPIC, а часть нет, это то, что один из ваших int global s будет использовать эту таблицу для определения адреса, а другая часть - нет.

Если у вас есть два общих объекта, связанных с -fPIC, но ваша основная программа отсутствует, то у вас все равно будет два адреса для int global, один из которых будет использовать глобальную таблицу смещений, а другой - только локальный по отношению к коду без PIC. .

Есть действительно отличная дискуссия о PIC против Pic против Non PIC , если вы хотите читать дальше.

1 голос
/ 04 сентября 2011

По умолчанию, когда создание исполняемых ссылок на переменные выполняется внутренне, с фиксированным смещением и без перемещения.

Однако вы передаете -fPIC, и доступ к глобальным данным преобразуется в доступ черезGOT и GOT перемещения добавлены.

...