静态库代码对驻留在应用程序代码中的外部结构使用了错误的地址

Static library code uses wrong address for extern struct residing in application code

我这边出现了非常奇怪的错误。我正在为 Cortex-M4f 运行 Nucleus RTOS 编写固件。对于我的应用程序,我有一些预构建的静态库(例如 libexternal.a),它们需要一个必须由应用程序提供的全局结构(在静态库中声明为 extern)。

在我的应用程序代码中,我可以很好地访问该结构,但在静态库的代码中,我总是会遇到 HardFault 中断。

通过调试我发现处理器试图访问错误地址上的结构。这是一些示例伪代码:

appconfig.c

struct AppConfiguration g_appconfig = {

/* initialize everything statically */
};

main.c

include <staticlib.h>

void main(){
  g_appconfig.somemember = 1 /* this works */

  staticlib_lib_init();
}

下面的所有内容都是静态库的一部分,并且在编译应用程序之前预先构建。

appconfig.h

struct AppConfiguration{
  uint32_t somemember;
};

staticlib.h

#include "appconfig.h"
extern struct AppConfiguration g_appconfig;

void static_lib_init();

staticlib.c

#include "staticlib.h"

void static_lib_init(){

  g_appconfig.somemember = 1 /* causes a HardFault */
}

静态库编译标志:

-ffunction-sections
-fdata-sections
-fno-builtin-memcpy
-DARM_MATH_CM4=1
-mthumb
-mcpu=cortex-m4
-mfloat-abi=soft
-fPIC
-Wno-unused-but-set-variable

以及带有标志的应用程序:

-ffunction-sections
-fdata-sections
-fno-builtin-memcpy
-mthumb
-mcpu=cortex-m4
-g
-mfloat-abi=soft

通过调试我发现静态库试图在错误的内存地址访问g_appconfig。例如

g_appconfig 从地址 0x2000061c 开始,static_lib_init() 尝试在地址 0xff7f4342 访问它。我的 SRAM 从 0x2000000 开始是 320k,我的 ROM 从 0x8000000 开始是 2MB。所以访问 0xff 处的内存是没有意义的......(可能是一些硬件寄存器或其他任何东西)。

static_lib_init() 的反汇编如下所示:

00000000 <static_lib_init>:
   0:   b5f0        push    {r4, r5, r6, r7, lr}
   2:   b08f        sub sp, #60 ; 0x3c
   4:   af06        add r7, sp, #24
   6:   6178        str r0, [r7, #20]
   8:   6139        str r1, [r7, #16]
   a:   60fa        str r2, [r7, #12]
   c:   60bb        str r3, [r7, #8]
   e:   4cf9        ldr r4, [pc, #996]  ; (3f4 <static_lib_init+0x3f4>)
  10:   447c        add r4, pc
  12:   4bf9        ldr r3, [pc, #996]  ; (3f8 <static_lib_init+0x3f8>)
  14:   58e3        ldr r3, [r4, r3]
  16:   461a        mov r2, r3
  18:   2301        movs    r3, #1
  1a:   f8c2 30d0   str.w   r3, [r2, #208]  ; 0xd0

r2 应该包含 g_appconfig 的起始地址(#208 是我想要在真实世界代码中访问的元素的偏移量),但是在调试时包含 0xff7f4342.

知道这是怎么发生的吗?链接器不应该在链接时替换生成的静态库中 g_appconfig 的地址吗?

如果我自己无法测试,我无法给你一个肯定的答案,但我猜问题是你正在用 -fPIC 构建你的库,但你的主要应用不是。

请记住,当您要求编译器生成与位置无关的代码时,您也在要求它生成与位置无关的数据。在您的情况下,全局变量 g_appconfig 将位于链接器确定的固定位置。

尝试删除库构建中的 -fPIC 选项。由于您只是静态链接,所以您并不真正需要它,而且它更有可能损害您的性能而不是帮助。