Skip to content

RISC-V: explicitly specified and synthesized .loc directives are incompatible with -mrelax #62535

@MaskRay

Description

@MaskRay

https://maskray.me/blog/2021-03-14-the-dark-side-of-riscv-linker-relaxation#line-number-information-for-assembly-files

The GNU assembler and LLVM integrated assembler both create a .debug_line section for assembly files that have .file and .loc directives.
When -g is specified for assembly files without these directives, debug information is synthesized, including line number information.

However, the LLVM integrated assembler has a bug that creates issues for -mrelax with .debug_line for both explicitly specified and synthesized .loc directives.
This is due to MCDwarfLineTable::emitOne calling MCObjectStreamer::emitDwarfAdvanceLineAddr to emit line table opcodes for a section.

For an assembly file, createRISCVELFStreamer is used to create a MCObjectStreamer instance with a MCAssembler object.
For a C/C++ file, createRISCVObjectTargetStreamer is used to create a MCObjectStreamer instance without a MCAssembler object.

When a MCAssembler object is used, label differences in the line number information are incorrectly foldable.
The LLVM integrated assembler will emit special opcodes that hard code instruction offsets, which can become incorrect when the instruction offset changes due to linker relaxation.

#!/bin/sh -e
cat > x.c <<eof
void f();
void _start() {
  f();
  f();
  f();
}
eof
# C to object file: correct DW_LNS_fixed_advance_pc
clang --target=riscv64 -g -c x.c
llvm-dwarfdump --debug-line -v x.o | grep \ DW_LNS_fixed_advance_pc

# Assembly to object file with synthesized line number information: incorrect special opcodes
clang --target=riscv64 -S x.c && clang --target=riscv64 -g -c x.s
llvm-dwarfdump --debug-line -v x.o | grep \ DW_LNS_fixed_advance_pc; test $? -eq 1

# Assembly with .loc to object file: incorrect special opcodes
clang --target=riscv64 -S -g x.c && clang --target=riscv64 -c x.s
llvm-dwarfdump --debug-line -v x.o | grep \ DW_LNS_fixed_advance_pc; test $? -eq 1

Using -S and -c on one source file is not commonly used to build projects.
However, clang --target=riscv64 -g -c x.s is somewhat common. My suggestion is to remove -g for now.
Synthesized debug information is not very useful anyway.

This can be worked around in several places, but that would further complicate the brittle part. I'd like to take some time figuring out the logic and coming up with a patch.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions