Подтвердить что ты не робот

Глобальные переменные, общие библиотеки и -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, глобальным в main.c и глобальным в lib.c являются одни и те же переменные:

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

без -fPIC, global в lib.c не коррелирует с глобальным в 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-generiС# 48-Ubuntu SMP Пт Июл 29 19:02:55 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux

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

4b9b3361

Ответ 1

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

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

Там действительно отличная дискуссия по PIC vs pic vs non PIC, если вы хотите читать дальше.

Ответ 2

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

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