[Bug debug/104460] New: [RISCV] Incorrect DW_AT_high_pc for assembly source with linker relaxation

joseph.faulls at imgtec dot com gcc-bugzilla@gcc.gnu.org
Wed Feb 9 11:54:04 GMT 2022


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

            Bug ID: 104460
           Summary: [RISCV] Incorrect DW_AT_high_pc for assembly source
                    with linker relaxation
           Product: gcc
           Version: 11.1.0
               URL: https://github.com/riscv-collab/riscv-gnu-toolchain
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: debug
          Assignee: unassigned at gcc dot gnu.org
          Reporter: joseph.faulls at imgtec dot com
                CC: kito.cheng at gmail dot com
  Target Milestone: ---
            Target: riscv32-unknown-elf

Created attachment 52386
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=52386&action=edit
Referenced assembly source

When using an assembly source, relocations are not added for DW_AT_high_pc in
the DIE, like they are if compiled from a c source. Therefore, there is no
fixup for DW_AT_high_pc after linker relaxation, so the value is wrong.

In some cases, this causes gdb to be unable to break correctly on code that is
placed directly after the code from the assembly source. (I presume) This is
because of a mismatch between what the DIE says, and what's actually placed.
E.G the DIE says code from the assembly source ranges from 0x0 to 0x60, when in
fact it actually goes from 0x0 to 0x30, and the subsequent code from a
different source starts at 0x32, causing an overlap/mismatch.

This problem can be observed by turning linker relaxation off/on for c/asm
sources and looking at the dwarfdump from the resulting elf's. 

The asm source used in this example is attached and is taken from the newlib
crt0.S (just as an example that triggers linker relaxation). The c source here
is simply just the asm source wrapped in an __asm__ call. main.c is an empty
main function just so something gets placed after.

Compilation commands:
> riscv32-unknown-elf-gcc myfunc.s -c -o myfunc-asm-no-relax.o -g -march=rv32imac -mabi=ilp32 -O0 -mno-relax
> riscv32-unknown-elf-gcc myfunc.s -c -o myfunc-asm.o -g -march=rv32imac -mabi=ilp32 -O0
> riscv32-unknown-elf-gcc myfunc.c -c -o myfunc-c-no-relax.o -g -march=rv32imac -mabi=ilp32 -O0 -mno-relax
> riscv32-unknown-elf-gcc myfunc.c -c -o myfunc-c.o -g -march=rv32imac -mabi=ilp32 -O0

Linking:
> riscv32-unknown-elf-gcc myfunc-asm-no-relax.o main.c -o myfunc-asm-no-relax.elf -march=rv32imac -mabi=ilp32 -nostartfiles -g
> riscv32-unknown-elf-gcc myfunc-asm-.o main.c -o myfunc-asm.elf -march=rv32imac -mabi=ilp32 -nostartfiles -g
> riscv32-unknown-elf-gcc myfunc-c-no-relax.o main.c -o myfunc-c-no-relax.elf -march=rv32imac -mabi=ilp32 -nostartfiles -g
> riscv32-unknown-elf-gcc myfunc-c.o main.c -o myfunc-c.elf -march=rv32imac -mabi=ilp32 -nostartfiles -g

Dwarfdumps: (objdump --dwarf)

myfunc-c-no-relax.elf
>    <1a>   DW_AT_low_pc      : 0x10084
>    <1e>   DW_AT_high_pc     : 0x60

myfunc-c.elf
>      <1a>   DW_AT_low_pc      : 0x10084
>      <1e>   DW_AT_high_pc     : 0x3a

myfunc-asm-no-relax.elf
>    <11>   DW_AT_low_pc      : 0x10084
>    <15>   DW_AT_high_pc     : 82

myfunc-asm.elf
>    <11>   DW_AT_low_pc      : 0x10084
>    <15>   DW_AT_high_pc     : 82


I did try and have a crack at fixing this, but got a bit overwhelmed. If anyone
can shed some more light on this and give pointers, I could give it another go.

LLVM does not have this bug; however, I did notice how it generates the debug
information for c/asm sources differently: the .c source uses the AT_high_PC
offset with relocations, but the .s source uses an absolute AT_high_PC with a
different relocation (I think it was a relocation such that it uses data
elsewhere. Maybe the value in .debug_aranges?)


More information about the Gcc-bugs mailing list