c - 如何在 C 中的共享库中使用外部符号
问题描述
我正在尝试编译以下测试文件以创建共享库:
答案.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)
}
添加.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 个文件“answer.c”“add.c”创建一个共享库,我正在使用以下命令:
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
想知道我是否在这里遗漏了什么。还想知道如何在共享库中使用外部符号。
解决方案
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
推荐阅读
- linux - 如果在 csv 文件中找到匹配项,如何获取整个记录
- sql - 如何在 Firebird 中使用声明语句嵌套匿名块?
- unix - 在 UNIX 的 txt 文件中按列计算非空行数
- openturns - 如何在 OpenTURNS 中估计混合模型的参数?
- android - 如何将数据从 Fragment 发送到 FirebaseAdapter 中的其他 Fragment,使用 model.class 到 getPid
- java - spring boot 工具套件安装
- firebase - 如何计算“Google BigQuery”中打开的推送通知
- vuejs2 - Vuex:硬刷新期间数据有时会“未定义”
- arm - 如何使用任何引脚在外部中断时实现 Adafruit Feather M0 睡眠和唤醒?
- c++ - 如何使用 mysql-cppconn 中的 get_driver_instance_by_name(const char * const clientlib) 函数?