Глобальные переменные, разделяемые библиотеки и эффект -fPIC

Я сделал фрагмент кода, который состоит из динамической библиотеки (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 - версия: 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:55 UTC 2011 x86_64 x86_64 x86_64 GNU / Linux

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


person yota    schedule 04.09.2011    source источник
comment
Связанный: stackoverflow.com/q/7216244/168175   -  person Flexo    schedule 04.09.2011


Ответы (2)


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

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

Есть действительно отличное обсуждение PIC, pic и non PIC, если вы хотите читать дальше.

person Flexo    schedule 04.09.2011

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

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

person Gregory Pakosz    schedule 04.09.2011