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

            Bug ID: 97754
           Summary: arm/lib1funcs.S (RETLDM): CFI may be incorrect
           Product: gcc
           Version: 11.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libgcc
          Assignee: unassigned at gcc dot gnu.org
          Reporter: martingalvan at sourceware dot org
  Target Milestone: ---

Hi all, I'm looking at the RETLDM macro for the ARM libgcc code:

.macro  RETLDM  regs=, cond=, unwind=, dirn=ia
#if defined (__INTERWORKING__)
        .ifc "\regs",""
        ldr\cond        lr, [sp], #8
        .else
# if defined(__thumb2__)
        pop\cond        {\regs, lr}
# else
        ldm\cond\dirn   sp!, {\regs, lr}
# endif
        .endif
        .ifnc "\unwind", ""
        /* Mark LR as restored.  */
97:     cfi_pop 97b - \unwind, 0xe, 0x0
        .endif
        bx\cond lr
#else
<...>
.endm

Here we can see that for the __INTERWORKING__ case, some CFI data is emitted if
we have an 'unwind' argument. However, I believe this may be wrong if a RETLDM
macro appears in the middle of another function. For the __INTERWORKING__ case,
the resulting output would be e.g:

pop {r4, r5, lr}
cfi_pop <...>
bx  lr
<rest of the function>

Here, 'cfi_pop' would affect the rest of the function unless the caller is
careful enough to restore the CFI status for lr after doing RETLDM. This can
happen e.g. if we pass a 'cond' argument, which means the branch may not be
taken.

Unless I'm mistaken, the way to fix this would be to introduce a couple of
.cfi_remember/restore_state directives:

    .ifnc "\unwind", ""
        /* Mark LR as restored.  */
        .cfi_remember_state
97:     cfi_pop 97b - \unwind, 0xe, 0x0
    .endif

    bx\cond lr

    .ifnc "\unwind", ""
        .cfi_restore_state
    .endif

If this is correct, I'll send in a patch to add this change.

Speaking of this file, I have a couple more questions:

1. The file is defining macros like cfi_start, cfi_push, etc which insert the
CFI data directly in binary form. Why can't we use gas' .cfi_* directives as we
do elsewhere? If we can, I'll send a separate patch to add this change as well.
2. Why is the __INTERWORKING__ macro only defined for ARMv4t? I'm not saying
that this is wrong, just curious.

Thanks.

Reply via email to