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).