https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128026
Bug ID: 128026
Summary: [DebugInfo] Invalid CFI register encoding in
output_cfa_loc and output_cfa_loc_raw
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: debug
Assignee: unassigned at gcc dot gnu.org
Reporter: wujielun402 at gmail dot com
Target Milestone: ---
GCC emits invalid CFI for x86-64 APX registers r16 and r17 (DWARF register
numbers 130 and 131). The register operand of DW_CFA_expression requires
ULEB128 encoding, but GCC writes it as a single raw byte.
Reproducer source (repro.c):
typedef unsigned long long u64;
__attribute__ ((noinline, noclone)) u64
save_extended_reg_with_realign (u64 input)
{
register unsigned long value __asm__ ("r16") = input;
register unsigned long other __asm__ ("r17") = input + 1;
volatile unsigned char aligned[64] __attribute__ ((aligned (64)));
volatile unsigned char fixed[256];
aligned[0] = (unsigned char) input;
fixed[0] = aligned[0];
__asm__ volatile ("" : "+r" (value), "+r" (other), "+m" (aligned)
: : "memory");
return value + other + fixed[0];
}
Compile to assembly:
gcc -O2 -g -gdwarf-5 -mapx-features=egpr -mtune=generic \
-mforce-drap -fcall-saved-r16 -fcall-saved-r17 -S repro.c -o repro.s
Compiler Explorer example: https://godbolt.org/z/1jG66b1nn
For example, GCC emits:
.cfi_escape 0x10,0x82,0x2,0x76,0x70
.cfi_escape inserts raw CFI bytes. GCC intends the following fields:
0x10 DW_CFA_expression
0x82 Register 130 (r16), incorrectly encoded
0x02 Length of the following DWARF expression: 2 bytes
0x76,0x70 DW_OP_breg6 (rbp), with SLEB128 offset -16
The intended rule locates the saved r16 at memory address rbp - 16.
However, ULEB128 uses seven payload bits per byte, with the high bit
indicating continuation. Register 130 therefore requires 0x82,0x01.
A decoder instead reads the emitted 0x82,0x02 as register 258, then
0x76 as an expression length of 118 bytes, misparsing subsequent bytes.
The correct encoding is:
.cfi_escape 0x10,0x82,0x1,0x2,0x76,0x70
Likewise, r17 requires 0x83,0x01 rather than just 0x83.
The example above exercises output_cfa_loc_raw. Source review identifies
at least two affected functions in gcc/dwarf2cfi.cc:
output_cfa_loc uses dw2_asm_output_data (1, r, NULL).
output_cfa_loc_raw uses fprintf (asm_out_file, "%#x,", r).
Both functions emit the register number without ULEB128 encoding. Both
need correction for DW_CFA_expression and DW_CFA_val_expression.