什么时候使用 .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 使用 exidx
和 extab
部分来进行堆栈跟踪。
简而言之,exidx
是例程开始地址和extab
表索引的排序表。通过exidx
进行二分搜索将找到对应的extab
条目。 extab
条目包含有关此例程中Note1 的堆栈的详细信息。它提供了有关例程在堆栈中存储的内容的详细信息。
如果注释掉的部分(r 变量赋值)未注释,则 .ARM.exidx 会出现,否则不会!现在可以解释了吗???
当你有*r++ = (comp)tmp;
这个语句时,编译器不能把所有的变量都保存在寄存器中,需要使用栈(或者至少fp
)。这会导致它发出 exidx
和 extab
数据。
有一些解决方案。如果您不需要堆栈跟踪或异步功能,可以同时丢弃 exidx
和 extab
。可以使用 gnu 工具/gcc 使用 -mapcs-frame
来完成更简单的堆栈展开;然后fp
将始终用于存储前一个堆栈帧(存储其调用者fp
等)。实际的桌子并没有那么大,放松的例程也相当简单。拥有不会污染正常程序路径的表或使用像-mapcs-frame
这样的寄存器可能会产生
参考:ATPCS Link and frame pointer explainedStructure of ARM extab
注意1:这是在序言对堆栈进行调整之后。注意2:ex
是例外,但不只是为了C++ 异常。
【讨论】:
以上是关于什么时候使用 .ARM.exidx的主要内容,如果未能解决你的问题,请参考以下文章
什么时候使用session?什么时候使用application?