Bug 31654 - gas: Bad SFrame information when assembling with listing
Summary: gas: Bad SFrame information when assembling with listing
Status: UNCONFIRMED
Alias: None
Product: binutils
Classification: Unclassified
Component: gas (show other bugs)
Version: 2.43 (HEAD)
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-04-18 09:31 UTC by Jens Remus
Modified: 2024-04-25 23:29 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jens Remus 2024-04-18 09:31:10 UTC
The assembler generates bad SFrame information when assembling the following CFI directive sequence with option "-Wa,-a" to generate a listing on a SFrame enabled target that uses FP and RA tracking:

.cfi_offset <fp-regno>, <fp-offset>
.cfi_offset <ra-regno>, <ra-offset> 

This causes multiple SFrame FREs for the same PC start address to be generated.

The reason is that with listings enabled there is an additional DWARF DW_CFA_advance_loc CFI instruction with zero advance between both DW_CFA_offset instructions, that the DWARF .eh_frame generator is able to process correctly, but causes the .sframe generator to choke.
Comment 1 Jens Remus 2024-04-18 09:38:24 UTC
Following is an example on s390x. Note that the following patch series are required for s390x:

- sframe: Enhancements to SFrame info generation
  https://sourceware.org/pipermail/binutils/2024-April/133591.html

- s390: Initial support to generate SFrame info from CFI directives in assembler
  https://sourceware.org/pipermail/binutils/2024-April/133597.html

With patch "gas: Skip SFrame FDE if FP without RA on stack" from above series reverted:

$ cat test_fpra_min.s
        .cfi_sections .sframe, .eh_frame
        .cfi_startproc
        stmg    %r11,%r15,88(%r15)
        .cfi_rel_offset 11, 88
        .cfi_rel_offset 14, 112
        la      %r11,0
        la      %r14,0
.Lreturn:
        lmg     %r11,%r15,88(%r15)
        .cfi_restore 14
        .cfi_restore 11
        br      %r14
        .cfi_endproc

$ as test_fpra_min.s -o test_fpra_without-alh.o
$ as -Wa,-alh test_fpra_min.s -o test_fpra_with_alh.o

$ ojbdump --sframe test_fpra_without-alh.o
...
  Function Index :

    func idx [0]: pc = 0x0, size = 22 bytes
    STARTPC         CFA       FP        RA
    0000000000000000  sp+160    u         u
    0000000000000006  sp+160    c-72      c-48
    0000000000000014  sp+160    u         u

$ objdump --sframe test_fpra_with_alh.o
...
  Function Index :

    func idx [0]: pc = 0x0, size = 22 bytes
    STARTPC         CFA       FP        RA
    0000000000000000  sp+160    u         u
    0000000000000006  sp+160    u         c-72
    0000000000000006  sp+160    c-72      c-48
    0000000000000014  sp+160    u         c-72
    0000000000000014  sp+160    u         u

Note that the FP-tracking information erroneously being displayed in the RA-tracking column, is why the patch "gas: Skip SFrame FDE if FP without RA on stack" got introduced.

The outputs of "objdump -Wf" and "objdump -WF" are identical in both cases (with and without option "-alh").

Debugging of the SFrame processing of the DWARF CFI instructions shows that with option "-a" there are additional DW_CFA_advance_loc:

DW_CFA_def_cfa: reg=15 offset=160
DW_CFA_advance_loc: lab1=L0, lab2=L0
DW_CFA_offset: reg=11 offset=-72
DW_CFA_advance_loc: lab1=L0, lab2=L0   <-- only with -a
DW_CFA_offset: reg=14 offset=-48
DW_CFA_advance_loc: lab1=L0, lab2=L0
DW_CFA_restore: reg=14
DW_CFA_advance_loc: lab1=L0, lab2=L0   <-- only with -a
DW_CFA_restore: reg=11

Debugging of the CFI directive processing in gas/dw2gencfi.c shows the following:

- With option "-a" cfi_add_advance_loc() is invoked more often in dot_cfi() due to the condition (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now) evaluating to true.

- output_cfi_insn() of case DW_CFA_advance_loc enters the condition (symbol_get_frag (to) == symbol_get_frag (from)) without option "-a" and enters the else condition with option "-a". The else path has an interesting comment that suggests that there is logic to relax an advance by zero at a later stage:

"... Call frag_grow with the sum of room needed by frag_more and frag_var to preallocate space ensuring that the DW_CFA_advance_loc4 is in the fixed part of the rs_cfa frag, so that the relax machinery can remove the advance_loc should it advance by zero."

I don't have a clue how to resolve this potential issue in the SFrame generation. I could not figure out how to detect the advance of zero in the SFrame processing of DW_CFA_advance_loc, so that it could be treated special.
Comment 2 Indu Bhagat 2024-04-25 23:29:45 UTC
This is repeatable on other arches too using binutils-gdb master.

One aarch64:

$ cat test.s 
        .cfi_startproc
        .long 0
        .cfi_def_cfa_offset 8
        .long 0
        .cfi_rel_offset 29, 16
        .cfi_rel_offset 30, 24
        .long 0
        .cfi_endproc


$ as --gsframe test.s -o test.o
$ objdump --sframe test.o
    ...
    func idx [0]: pc = 0x0, size = 12 bytes
    STARTPC         CFA       FP        RA           
    0000000000000000  sp+0      u         u            
    0000000000000004  sp+8      u         u            
    0000000000000008  sp+8      c+8       c+16         

$ as --gsframe -alh test.s -o test.o
   ...
$ objdump --sframe test.o
    ...
    func idx [0]: pc = 0x0, size = 12 bytes
    STARTPC         CFA       FP        RA           
    0000000000000000  sp+8      c+8       c+16         

Similar testcase can be easily arrived at for x86_64 as well.