什么时候使用 .ARM.exidx

Posted

技术标签:

【中文标题】什么时候使用 .ARM.exidx【英文标题】:When is .ARM.exidx is used 【发布时间】:2014-02-26 22:23:33 【问题描述】:

我正在使用 mbxxx 目标开发 Contiki 2.7。在构建我的代码时,链接器抱怨 .ARM.exidx 和 .data 部分重叠。在修改了链接器脚本 contiki-2.7/cpu/stm32w108/gnu-stm32w108.ld 之后,我通过替换解决了这个问题:

__exidx_start = .;
__exidx_end = .;

与:

.ARM.exidx : 
    __exidx_start = .;
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    __exidx_end = .;
 >ROM_region

后来,当我尝试使用 objdump -h 查看其他示例应用程序的标题列表时,我没有找到这个特定的 .ARM.exidx 部分,而它存在于我的应用程序中。谷歌搜索 .ARM.exidx 让我发现它用于一些 c++ 异常处理。既然我的代码是纯 C 代码,为什么这部分会出现在我的代码中? .ARM.exidx 通常在什么时候出现在代码中,它的用途是什么?

================================================ ====================================

不,我没有任何这样的编译器选项。我实际上正在使用 AxTLS api 并撕下证书处理代码并将其移植到 contiki。在进一步的挖掘中,我发现了 bigint 实现中的可疑行为。简而言之……这是 bigint.c 文件中的函数体:

static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b)

   int j = 0, n = bia->size;
   bigint *biR = alloc(ctx, n + 1);
   comp carry = 5;
   comp *r = biR->comps;
   comp *a = bia->comps;

   check(bia);

   /* clear things to start with */
   memset(r, 0, ((n+1)*COMP_BYTE_SIZE));


   do
   
       long_comp tmp = *r + (long_comp)a[j]*b + carry;
   //    *r++ = (comp)tmp;              /* downsize */
       carry = (comp)(tmp >> COMP_BIT_SIZE);
    while (++j < n);

  // *r = carry;
  bi_free(ctx, bia);

  return trim(biR);

如果注释掉的部分(r 变量赋值)未注释,则 .ARM.exidx 会出现,否则不会!现在可以解释了吗???

================================================ ====================================

我在alloc() 的实现中没有发现任何不寻常的东西。在代码的某个单独区域中使用了 2 个 alloca() 引用,我将其替换为 malloc()free(),但这也没有解决问题。 alloc() 实现只调用 malloc(),realloc()free()

【问题讨论】:

你好@user2668988!请注意,如果您想为您的问题添加更多详细信息,可以在此处edit您的问题。 biR 是使用alloca() 还是alloc() 是如何实现的?编译器可以使用相同的 C++ 机制来跟踪 alloca() 类型分配。当您注释掉 r 时,通过优化,alloc() 不会发生。 我在alloc()的实现中没有发现任何不寻常的东西。在代码的某个单独区域中使用了 2 个 alloca() 引用,我将其替换为 malloc()free(),但这也不能解决问题。 alloc() 实现只调用 malloc(),realloc()free() 【参考方案1】:

.ARM.exidx 是包含展开堆栈信息的部分。如果您的 C 程序具有打印出堆栈回溯的函数,则这些函数可能取决于此部分是否存在。

也许在您的编译器选项中寻找-funwind-tables-fexceptions 标志。

【讨论】:

我相信-funwind-tables 选项默认是打开的,至少在近年来的 CodeSourcery 工具链中是这样。没有它,调试器中的回溯非常困难。 那么如何禁用这个选项呢? 找到标志并删除它? 您不能“删除”隐式标志,但有时可以添加 cointer 标志(如 -fno-unwind-tables【参考方案2】:

添加到 tangrs 的响应中,如果您使用 gcc -v,则可以转储编译期间使用的默认选项。

GCC 的所有选项(隐式和显式)选项都传递给 GCC 的 cc1 程序。

【讨论】:

【参考方案3】:

此功能在“C”中使用。 ARM APCS 仅使用帧指针来恢复堆栈。较新的 AAPCS 有时会使用表格。堆栈展开、信号处理程序和其他异步“C”功能使用这些机制。对于裸机嵌入式设备,它可用于跟踪堆栈。例如,Linux 的 unwind.c 使用 exidxextab 部分来进行堆栈跟踪。

简而言之,exidx 是例程开始地址和extab 表索引的排序表。通过exidx 进行二分搜索将找到对应的extab 条目。 extab 条目包含有关此例程中Note1 的堆栈的详细信息。它提供了有关例程在堆栈中存储的内容的详细信息。

如果注释掉的部分(r 变量赋值)未注释,则 .ARM.exidx 会出现,否则不会!现在可以解释了吗???

当你有*r++ = (comp)tmp;这个语句时,编译器不能把所有的变量都保存在寄存器中,需要使用栈(或者至少fp)。这会导致它发出 exidxextab 数据。


有一些解决方案。如果您不需要堆栈跟踪或异步功能,可以同时丢弃 exidxextab。可以使用 gnu 工具/gcc 使用 -mapcs-frame 来完成更简单的堆栈展开;然后fp 将始终用于存储前一个堆栈帧(存储其调用者fp 等)。实际的桌子并没有那么大,放松的例程也相当简单。拥有不会污染正常程序路径的表或使用像-mapcs-frame 这样的寄存器可能会产生

参考:ATPCS Link and frame pointer explainedStructure of ARM extab

注意1:这是在序言对堆栈进行调整之后。注意2:ex是例外,但不只是为了C++ 异常。

【讨论】:

以上是关于什么时候使用 .ARM.exidx的主要内容,如果未能解决你的问题,请参考以下文章

什么时候使用flush()?

什么时候可以使用 Javascript,什么时候不可以?

什么时候使用内联函数,什么时候不使用它?

什么时候使用session?什么时候使用application?

什么时候应该使用 Docker,什么时候应该使用虚拟机? [复制]

什么时候使用泛型方法,什么时候使用通配符?