如何在C中的共享库中使用extern符号

时间:2018-04-29 16:01:44

标签: c gcc shared-libraries linker-errors extern

我正在尝试编译以下测试文件以创建共享库:

answer.c

#include <stdio.h>    
#include "add.h"    
extern int myvar();

int answer()
{    
    printf("\r\n myvar:%d \r\n", myvar());    
    setSummand(20);    
    return add(22);  // Will return 42 (=20+22)   
}

add.c

#include <stdio.h>

int gSummand;    

void setSummand(int summand)
{    
    printf("1Library is initialized\n");    
    gSummand = summand;
}

int add(int summand)
{    
  return gSummand + summand;    
}

我想从2个文件中创建一个共享库&#34; answer.c&#34; &#34; add.c&#34;,我使用以下命令:

gcc -c answer.c  -o answer.o
gcc -c add.c  -o add.o
gcc -shared add.o answer.o -o libtest.so

但是第三个命令会出现以下错误:

answer.o:answer.c:(.text+0x9): undefined reference to `myvar'
answer.o:answer.c:(.text+0x9): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `myvar'
collect2: error: ld returned 1 exit status

如果我使用以下命令创建静态库而不是动态库,则相同的设置链接成功。因此,如果我尝试执行以下命令,则不会看到任何错误:

ar rcs libtest.a add.o answer.o

想知道我是否在这里失踪了。还想知道如何在共享库中使用外部符号。

1 个答案:

答案 0 :(得分:2)

ELF共享库需要与位置无关。它们将映射到可执行文件的地址空间中,该地址在运行时才知道。这意味着没有绝对地址调用指令,例如可能用于调用myvar()

当您将源代码编译为目标文件时,需要指定-fpic,此时这些目标文件将放入共享库中。这告诉编译器生成不使用绝对地址等的代码,因此它可以与位置无关。

使用此库的main.c文件示例:

extern int answer(void);
int myvar() { return 1; }
int main(void) { return answer(); }

没有-fpic的示例:

[test]$ gcc -c add.c
[test]$ gcc -c answer.c 
[test]$ gcc -shared add.o answer.o -o libtest.so
/usr/bin/ld: add.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: answer.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status

-fpic的示例:

[test]$ gcc -fpic -c add.c
[test]$ gcc -fpic -c answer.c
[test]$ gcc -shared add.o answer.o -o libtest.so
[test]$ gcc main.c libtest.so
[test]$ LD_LIBRARY_PATH=. ./a.out

 myvar:1 
1Library is initialized