您应该使用 -fPIC 进行编译。见how to recompile with -fPIC
非 PIC 代码在迁移到另一个地址时需要修改。二进制代码和数据的这些修改称为重定位。有许多不同类型的搬迁。它们可能涉及将符号的绝对地址放入数据字中,或修改 MOVW 或 MOVT 指令的某些位以将部分常量放入指令本身。后一个是你的问题。
当您链接可执行文件时,静态链接器将执行所有这些重定位。如果您使用共享库,则动态链接器必须在可执行文件运行并动态链接到共享库时执行这些操作。
动态链接器可能不支持某些类型的重定位,称为文本重定位或 TEXTRELS。这些涉及使用实际代码修改文本段,并将值放入指令中。由于它修改了代码,共享库的那部分将不再在进程之间共享。您应该通过 -fPIC 使库位置独立,因此动态链接器不需要进行文本重定位。
您之前的代码可能没有导致编译器发出任何需要不受支持的重定位的内容。然后你添加的文件中有一些东西。例如,访问全局变量可以在 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指令中。动态链接器不支持这一点。如果代码是使用 -fPIC(或 -mword-relocations)编译的,编译器会产生不需要这些重定位的不同输出。
“protocol.o”具有不受支持的重定位,并且在您进行更改之前它不存在,或者没有使用,或者没有它们。如果 libservice.a 已经存在,请记住,静态库中的代码仅在使用时才包含在内。也许“protocol.o”没有被任何东西使用,但是你添加的任何东西都使用了它。