When is .ARM.exidx is used
Asked Answered
B

3

16

I am working on Contiki 2.7 with the mbxxx target. While building my code the linker complained about an overlap of .ARM.exidx and .data sections. After some tinkering around with the linker script contiki-2.7/cpu/stm32w108/gnu-stm32w108.ld I fixed the problem by replacing:

__exidx_start = .;
__exidx_end = .;

with:

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

Later when I tried to see the header listing of some other example applications by using objdump -h I did not find this particular .ARM.exidx section, while it is present in my application. Googling about .ARM.exidx led me to the fact that it is used for some c++ exception handling. Since my code is a pure C code, why is this section present on my code? When is generally .ARM.exidx present in code and what is its utility?


Well no, I don't have any such compiler options. I am actually using the AxTLS api and ripped out the certificate handling code and ported it to contiki. On some further digging I found a fishy behaviour in the bigint implementation. To be brief... here is the body of a function from the bigint.c file:

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);
}

If the commented out portions, (the r variable assignment) is uncommented, the .ARM.exidx thingy appears, otherwise it doesn't! Now can this be explained?


I didn't find anything out of the ordinary used in the implementation of alloc(). There were 2 references of alloca() used in some separate region of the code, which I replaced with malloc() and free(), but that didn't fix the problem either. alloc() implementation has only calls to malloc(),realloc() and free().

Brainard answered 3/2, 2014 at 12:17 Comment(3)
Hello @user2668988! Just as a heads up, if you want to add more detail to your question, you can edit your question here.Dymphia
Is biR using alloca() or how is alloc() implemented? The compiler may use the same C++ mechanism to track alloca() type allocations. When you comment out r, with optimizations, the alloc() won't happen.Flocculus
I didn't find any thing out of the ordinary used in the implementation of alloc(). There were 2 references of alloca() used in some separate region of the code, which I replaced with malloc() and free(), but that didn't fix the problem either. alloc() implementation has only calls to malloc(),realloc() and free()Brainard
F
22

.ARM.exidx is the section containing information for unwinding the stack. If your C program has functions that print out a stack backtrace, the functions will likely depend on this section being present.

Maybe look for a -funwind-tables or -fexceptions flag in your compiler options.

Fanni answered 3/2, 2014 at 12:45 Comment(4)
I believe the -funwind-tables option is on by default, at least in CodeSourcery toolchains of recent years. Without it, back-trace in the debugger is quite hard.Emmons
how to disable this option then?Brainard
Find the flag and remove it?Fanni
You cant "remove" implicit flag, but sometimes adding cointer flag is possible (like -fno-unwind-tables)Nainsook
F
7

This feature is used in 'C'. The ARM APCS uses only a frame pointer to restore a stack. The newer AAPCS uses tables on occasion. Stack unwinding, signal handlers and other asynchronous 'C' features use these mechanism. For a bare metal embedded device it can be used to trace a stack. For instance, Linux's unwind.c uses both exidx and extab sections to do a stack trace.

Briefly the exidx is a sorted table of routine start addresses and an extab table index. A binary search through the exidx will find the corresponding extab entry. The extab entry has details about the stack in this routineNote1. It gives details about what the routine is storing on the stack.

if the commented out portions, (the r variable assignment) is uncommented, the .ARM.exidx thingy appears, otherwise it doesn't! Now can this be explained???

When you have the statement *r++ = (comp)tmp;, the compiler can not hold all the variables in registers and needs to use the stack (or at least fp). This causes it to emit and exidx and extab data.


There are some solutions. It is fine to discard both exidx and extab if you don't need stack tracing or asynchronous functionality. Simpler stack unwinding can be done with gnu tools/gcc using -mapcs-frame; then fp will always be used to store the previous stack frame (which stores its callers fp, etc). The actual tables are not that big and the routines to unwind are fairly simple. It maybe <3% overhead to have the tables which don't pollute the normal program path or use a register like -mapcs-frame. Desirable on Cortex-A cpus with cache and usually more memory.

Reference: ATPCS Link and frame pointer explained
                  Structure of ARM extab

Note1: This is after the prologue makes an adjustment to the stack.
Note2: The ex is for exception, but it is not solely for C++ exceptions.

Flocculus answered 12/8, 2019 at 14:53 Comment(0)
E
2

Adding to tangrs' response, if you gcc -v, you can dump the default options used during compilation.

All options (implicit & explicit) options of GCC are passed to cc1 program of GCC.

Eugenieeugenio answered 27/1, 2015 at 9:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.