https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71978

            Bug ID: 71978
           Summary: -mrealignstack and the unwinder
           Product: gcc
           Version: 6.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: rianquinn at gmail dot com
  Target Milestone: ---

I think there is an issue with GCC 6.1, -mrealignstack and expressions. We use
-mrealignstack because without it, "-O3" crashes when we set the arch to
sandybridge (as SSE instructions are inserted, and the stack ends up being
misaligned). 

We have our own custome unwinder, and it worked great until we started testing
6.1 (i.e. this issue does not occur with 5.X). With 6.1, DWARF expressions are
used. It appears that the CFA offset "sign" is backwards. Here is offending
FDE:

00000d98 0000000000000044 00000d04 FDE cie=00000098
pc=0000000000019282..0000000000019d80
  Augmentation data:     96 63 00 00

  DW_CFA_advance_loc: 5 to 0000000000019287
  DW_CFA_def_cfa: r10 (r10) ofs 0
  DW_CFA_advance_loc: 9 to 0000000000019290
  DW_CFA_expression: r6 (rbp) (DW_OP_breg6 (rbp): 0)
  DW_CFA_advance_loc: 7 to 0000000000019297
  DW_CFA_def_cfa_expression (DW_OP_breg6 (rbp): -16; DW_OP_deref)
  DW_CFA_expression: r12 (r12) (DW_OP_breg6 (rbp): -8)
  DW_CFA_advance_loc: 8 to 000000000001929f
  DW_CFA_expression: r3 (rbx) (DW_OP_breg6 (rbp): -24)
  DW_CFA_advance_loc2: 2775 to 0000000000019d76
  DW_CFA_restore: r3 (rbx)
  DW_CFA_advance_loc: 2 to 0000000000019d78
  DW_CFA_restore: r10 (r10)
  DW_CFA_def_cfa: r10 (r10) ofs 0
  DW_CFA_advance_loc: 2 to 0000000000019d7a
  DW_CFA_restore: r12 (r12)
  DW_CFA_advance_loc: 1 to 0000000000019d7b
  DW_CFA_restore: r6 (rbp)
  DW_CFA_advance_loc: 4 to 0000000000019d7f
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

As you can see, the CFA is defined as -16 from rbp which is wrong. It should be
+16 from rbp. Besides the fact that it doesn't make sense for the CFA to be
inside the existing CFA... if the other registers are 0, -8 and -24... how
could the start of the CFA be -16, in the middle of register state. 

The result is RIP which is -8 from the CFA, ends up being a heap address and
the unwinder gets mad. To prove to myself that the offset should have been +16,
I swapped the sign just for CFA offset, and the unwinder worked great again. To
pull this hack off, I had to store a flag for DW_OP_breg6. When it's
calculating the location of the CFA, it swaps the sign, otherwise it keeps the
sign as is. Doing this, the unwinder successfully throws exceptions again. 

Just for more complete reference, here is an FDE from the same library that
doesn't use expressions. In this case, you can see the offset being +16... so
it's only an issue with 6.1 with -mrealignstack in FDEs that use expressions. 

000000b8 0000000000000024 00000024 FDE cie=00000098
pc=0000000000020b20..0000000000020b5d
  Augmentation data:     3f 6f 00 00

  DW_CFA_advance_loc: 1 to 0000000000020b21
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r6 (rbp) at cfa-16
  DW_CFA_advance_loc: 3 to 0000000000020b24
  DW_CFA_def_cfa_register: r6 (rbp)
  DW_CFA_advance_loc: 56 to 0000000000020b5c
  DW_CFA_restore: r6 (rbp)
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

Also... the GCC 6.1 compiler is x86_64-elf-g++ (i.e. generic 64bit cross
compiler).

Reply via email to