制作共享对象错误时如何修复局部符号'不能使用?
how to fix a local symbol' can not be used when making a shared object error?
我的 c 源文件编译失败,出现以下错误:
libservices.a(protocol.o): relocation R_ARM_MOVW_ABS_NC against `a local symbol' can not be used when making a shared object; recompile with -fPIC
libservices.a: error adding symbols: Bad value collect2.exe:
error: ld returned 1 exit status
除了在源目录中添加了一个额外的文件之外,我没有做任何更改,然后事情就开始折腾了。即使我没有使用 -fPIC
选项,它也可以在没有这些警告的情况下正常工作。由于我没有对 make 文件进行任何更改,所以我很想知道为什么会出现此错误,这是什么意思,以及如何解决此问题。感谢帮助。
这取决于您将哪种文件添加到源文件夹中。
例如,如果您添加一个新的库文件,并且该新库文件是根据 -fPIC 构建选项构建的,您可能会遇到类似的情况。
实际上,错误消息为您提供了足够的信息来解决问题。
通过“-fPIC”构建选项重新编译它就可以了。
- 如果您通过命令行构建,请在命令中添加“-fPIC”
线.
如果您是通过 Makefile 构建,请按如下方式修改 makefile:
CFLAGS += -fPIC
ARM编译器请参考
- GCC编译器请参考
您应该使用-fPIC 进行编译。参见 how to recompile with -fPIC
非PIC代码在迁移到另一个地址时需要修改。这些二进制代码和数据的修改称为重定位。有许多不同类型的搬迁。它们可能涉及将符号的绝对地址放入数据字,或修改 MOVW 或 MOVT 指令的某些位以将部分常量放入指令本身。后一个是你的问题。
当您 link 您的可执行文件时,静态 linker 将执行所有这些重定位。如果您使用共享库,那么动态 linker 必须在可执行文件 运行 和动态 linked 到共享库时执行它们。
动态 linker 可能不支持某些类型的重定位,称为文本重定位或 TEXTRELS。这些涉及使用实际代码修改文本段,并将值放入指令中。由于它修改了代码,共享库的那部分将不再在进程之间共享。您应该通过 -fPIC 使库位置独立,因此动态 linker 不需要进行文本重定位。
您之前的代码可能没有导致编译器发出任何需要不受支持的重定位的内容。然后你添加的文件中有一些东西。例如,访问全局变量可以在 ARM 上触发此操作。
int x = 1;
void foo(void) { x=42; }
编译为:
movw r3, #:lower16:x
mov r2, #42
movt r3, #:upper16:x
str r2, [r3]
bx lr
x的地址的下半部分和上半部分需要放在movw和movt指令中。动态 linker 不支持这个。如果代码是使用 -fPIC(或 -mword-relocations)编译的,编译器将产生不需要这些重定位的不同输出。
"protocol.o" 具有不受支持的重定位,并且在您更改之前它不存在、未被使用或没有。如果 libservice.a 已经存在,请记住静态库中的代码仅在使用时才包含在内。也许 "protocol.o" 没有被任何东西使用,但是你添加的任何东西都使用了它。
我的 c 源文件编译失败,出现以下错误:
libservices.a(protocol.o): relocation R_ARM_MOVW_ABS_NC against `a local symbol' can not be used when making a shared object; recompile with -fPIC
libservices.a: error adding symbols: Bad value collect2.exe:
error: ld returned 1 exit status
除了在源目录中添加了一个额外的文件之外,我没有做任何更改,然后事情就开始折腾了。即使我没有使用 -fPIC
选项,它也可以在没有这些警告的情况下正常工作。由于我没有对 make 文件进行任何更改,所以我很想知道为什么会出现此错误,这是什么意思,以及如何解决此问题。感谢帮助。
这取决于您将哪种文件添加到源文件夹中。 例如,如果您添加一个新的库文件,并且该新库文件是根据 -fPIC 构建选项构建的,您可能会遇到类似的情况。
实际上,错误消息为您提供了足够的信息来解决问题。 通过“-fPIC”构建选项重新编译它就可以了。
- 如果您通过命令行构建,请在命令中添加“-fPIC” 线.
如果您是通过 Makefile 构建,请按如下方式修改 makefile:
CFLAGS += -fPIC
ARM编译器请参考
- GCC编译器请参考
您应该使用-fPIC 进行编译。参见 how to recompile with -fPIC
非PIC代码在迁移到另一个地址时需要修改。这些二进制代码和数据的修改称为重定位。有许多不同类型的搬迁。它们可能涉及将符号的绝对地址放入数据字,或修改 MOVW 或 MOVT 指令的某些位以将部分常量放入指令本身。后一个是你的问题。
当您 link 您的可执行文件时,静态 linker 将执行所有这些重定位。如果您使用共享库,那么动态 linker 必须在可执行文件 运行 和动态 linked 到共享库时执行它们。
动态 linker 可能不支持某些类型的重定位,称为文本重定位或 TEXTRELS。这些涉及使用实际代码修改文本段,并将值放入指令中。由于它修改了代码,共享库的那部分将不再在进程之间共享。您应该通过 -fPIC 使库位置独立,因此动态 linker 不需要进行文本重定位。
您之前的代码可能没有导致编译器发出任何需要不受支持的重定位的内容。然后你添加的文件中有一些东西。例如,访问全局变量可以在 ARM 上触发此操作。
int x = 1;
void foo(void) { x=42; }
编译为:
movw r3, #:lower16:x
mov r2, #42
movt r3, #:upper16:x
str r2, [r3]
bx lr
x的地址的下半部分和上半部分需要放在movw和movt指令中。动态 linker 不支持这个。如果代码是使用 -fPIC(或 -mword-relocations)编译的,编译器将产生不需要这些重定位的不同输出。
"protocol.o" 具有不受支持的重定位,并且在您更改之前它不存在、未被使用或没有。如果 libservice.a 已经存在,请记住静态库中的代码仅在使用时才包含在内。也许 "protocol.o" 没有被任何东西使用,但是你添加的任何东西都使用了它。