diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -453,6 +453,12 @@ /// `MCAsmInfo::ExceptionsType == ExceptionHandling::None`. bool needsCFIForDebug() const; + // The symbol's address range will only be known after the linking when using + // relaxations. Hence, generate address range offsets as relocatable symbols + // and not as absolute delta from label difference as they might get resolved + // before linking. + virtual bool needRelocSymbolsForAddrRange() const { return false; } + /// Print to the current output stream assembly representations of the /// constants in the constant pool MCP. This is used to print out constants /// which have been "spilled to memory" by the code generator. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2774,13 +2774,12 @@ } template -static void emitRangeList( - DwarfDebug &DD, AsmPrinter *Asm, MCSymbol *Sym, const Ranges &R, - const DwarfCompileUnit &CU, unsigned BaseAddressx, unsigned OffsetPair, - unsigned StartxLength, unsigned EndOfList, - StringRef (*StringifyEnum)(unsigned), - bool ShouldUseBaseAddress, - PayloadEmitter EmitPayload) { +static void +emitRangeList(DwarfDebug &DD, AsmPrinter *Asm, MCSymbol *Sym, const Ranges &R, + const DwarfCompileUnit &CU, unsigned BaseAddressx, + unsigned OffsetPair, unsigned StartxLength, unsigned StartxEndx, + unsigned EndOfList, StringRef (*StringifyEnum)(unsigned), + bool ShouldUseBaseAddress, PayloadEmitter EmitPayload) { auto Size = Asm->MAI->getCodePointerSize(); bool UseDwarf5 = DD.getDwarfVersion() >= 5; @@ -2795,10 +2794,14 @@ for (const auto &Range : R) SectionRanges[&Range.Begin->getSection()].push_back(&Range); + bool NeedRelocSymbols = UseDwarf5 && Asm->needRelocSymbolsForAddrRange(); + if (NeedRelocSymbols) + ShouldUseBaseAddress = false; + const MCSymbol *CUBase = CU.getBaseAddress(); bool BaseIsSet = false; for (const auto &P : SectionRanges) { - auto *Base = CUBase; + auto *Base = NeedRelocSymbols ? nullptr : CUBase; if (!Base && ShouldUseBaseAddress) { const MCSymbol *Begin = P.second.front()->Begin; const MCSymbol *NewBase = DD.getSectionLabel(&Begin->getSection()); @@ -2845,12 +2848,22 @@ Asm->emitLabelDifference(End, Base, Size); } } else if (UseDwarf5) { - Asm->OutStreamer->AddComment(StringifyEnum(StartxLength)); - Asm->emitInt8(StartxLength); - Asm->OutStreamer->AddComment(" start index"); - Asm->emitULEB128(DD.getAddressPool().getIndex(Begin)); - Asm->OutStreamer->AddComment(" length"); - Asm->emitLabelDifferenceAsULEB128(End, Begin); + if (NeedRelocSymbols) { + // Generate indices into .debug_addr so they will need relocations + Asm->OutStreamer->AddComment(StringifyEnum(StartxEndx)); + Asm->emitInt8(StartxEndx); + Asm->OutStreamer->AddComment(" start index"); + Asm->emitULEB128(DD.getAddressPool().getIndex(Begin)); + Asm->OutStreamer->AddComment(" end index"); + Asm->emitULEB128(DD.getAddressPool().getIndex(End)); + } else { + Asm->OutStreamer->AddComment(StringifyEnum(StartxLength)); + Asm->emitInt8(StartxLength); + Asm->OutStreamer->AddComment(" start index"); + Asm->emitULEB128(DD.getAddressPool().getIndex(Begin)); + Asm->OutStreamer->AddComment(" length"); + Asm->emitLabelDifferenceAsULEB128(End, Begin); + } } else { Asm->OutStreamer->emitSymbolValue(Begin, Size); Asm->OutStreamer->emitSymbolValue(End, Size); @@ -2871,14 +2884,14 @@ // Handles emission of both debug_loclist / debug_loclist.dwo static void emitLocList(DwarfDebug &DD, AsmPrinter *Asm, const DebugLocStream::List &List) { - emitRangeList(DD, Asm, List.Label, DD.getDebugLocs().getEntries(List), - *List.CU, dwarf::DW_LLE_base_addressx, - dwarf::DW_LLE_offset_pair, dwarf::DW_LLE_startx_length, - dwarf::DW_LLE_end_of_list, llvm::dwarf::LocListEncodingString, - /* ShouldUseBaseAddress */ true, - [&](const DebugLocStream::Entry &E) { - DD.emitDebugLocEntryLocation(E, List.CU); - }); + emitRangeList( + DD, Asm, List.Label, DD.getDebugLocs().getEntries(List), *List.CU, + dwarf::DW_LLE_base_addressx, dwarf::DW_LLE_offset_pair, + dwarf::DW_LLE_startx_length, dwarf::DW_LLE_startx_endx, + dwarf::DW_LLE_end_of_list, llvm::dwarf::LocListEncodingString, + /* ShouldUseBaseAddress */ true, [&](const DebugLocStream::Entry &E) { + DD.emitDebugLocEntryLocation(E, List.CU); + }); } void DwarfDebug::emitDebugLocImpl(MCSection *Sec) { @@ -3113,8 +3126,8 @@ const RangeSpanList &List) { emitRangeList(DD, Asm, List.Label, List.Ranges, *List.CU, dwarf::DW_RLE_base_addressx, dwarf::DW_RLE_offset_pair, - dwarf::DW_RLE_startx_length, dwarf::DW_RLE_end_of_list, - llvm::dwarf::RangeListEncodingString, + dwarf::DW_RLE_startx_length, dwarf::DW_RLE_startx_endx, + dwarf::DW_RLE_end_of_list, llvm::dwarf::RangeListEncodingString, List.CU->getCUNode()->getRangesBaseAddress() || DD.getDwarfVersion() >= 5, [](auto) {}); diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp --- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -83,6 +83,8 @@ void emitFunctionEntryLabel() override; + bool needRelocSymbolsForAddrRange() const override; + private: void emitAttributes(); }; @@ -238,6 +240,13 @@ return AsmPrinter::emitFunctionEntryLabel(); } +bool RISCVAsmPrinter::needRelocSymbolsForAddrRange() const { + if (MF) + return MF->getSubtarget().hasFeature(RISCV::FeatureRelax); + + return TM.getMCSubtargetInfo()->hasFeature(RISCV::FeatureRelax); +} + // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() { RegisterAsmPrinter X(getTheRISCV32Target()); diff --git a/llvm/test/DebugInfo/RISCV/dwarf-riscv-range-list-relocs.ll b/llvm/test/DebugInfo/RISCV/dwarf-riscv-range-list-relocs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/RISCV/dwarf-riscv-range-list-relocs.ll @@ -0,0 +1,163 @@ +; REQUIRES: riscv-registered-target +; The LLVM IR is generated from the following source code with "clang -S -emit-llvm -target riscv32 -g -mrelax -ffunction-sections" +; int baz() +; +; { return 0; } +; int foo() +; +; { return baz(); } +; int bar() +; +; { return foo(); } + + +; RUN: llc -filetype=asm -mtriple=riscv32 -mattr="+relax" -target-abi=ilp32 -dwarf-version=5 --function-sections %s -o %t.s +; RUN: FileCheck -check-prefix=ASM -input-file %t.s %s +; RUN: llc -filetype=obj -mtriple=riscv32 -mattr="+relax" -target-abi=ilp32 -dwarf-version=5 --function-sections %s -o %t.o +; RUN: llvm-dwarfdump --verify %t.o +; RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=OBJ %s +; RUN: ld.lld %t.o -o %t.out +; RUN: llvm-dwarfdump --verify %t.out +; RUN: llvm-dwarfdump --debug-info --debug-addr --debug-rnglists %t.out | FileCheck -check-prefix=DWARFDUMP %s + + +; When using relaxations, since the symbol's actual address range will only be +; known after linking, make sure we do not generate address range offsets as +; label differences as they might get resolved before linking. Instead we +; generate indices into the .debug_addr so that they will need relocations which +; will be resolved during linking. + +; ASM: .section .debug_info,"",@progbits +; ASM: .Ldebug_info_start0: +; ASM-NEXT: .half 5 # DWARF version number +; ASM: .word 0 # DW_AT_low_pc +; ASM-NEXT: .byte 0 # DW_AT_ranges +; ASM-NEXT: .word .Laddr_table_base0 # DW_AT_addr_base +; ASM-NEXT: .word .Lrnglists_table_base0 # DW_AT_rnglists_base + +; ASM: .section .debug_rnglists,"",@progbits +; ASM: .Lrnglists_table_base0: +; ASM-NEXT: .word .Ldebug_ranges0-.Lrnglists_table_base0 +; ASM-NEXT: .Ldebug_ranges0: +; ASM-NEXT: .byte 2 # DW_RLE_startx_endx +; ASM-NEXT: .byte 0 # start index +; ASM-NEXT: .byte 3 # end index +; ASM-NEXT: .byte 2 # DW_RLE_startx_endx +; ASM-NEXT: .byte 1 # start index +; ASM-NEXT: .byte 4 # end index +; ASM-NEXT: .byte 2 # DW_RLE_startx_endx +; ASM-NEXT: .byte 2 # start index +; ASM-NEXT: .byte 5 # end index +; ASM-NEXT: .byte 0 # DW_RLE_end_of_list +; ASM-NEXT: .Ldebug_list_header_end0: + +; ASM: .section .debug_addr,"",@progbits +; ASM: .Laddr_table_base0: +; ASM-NEXT: .word .Lfunc_begin0 +; ASM-NEXT: .word .Lfunc_begin1 +; ASM-NEXT: .word .Lfunc_begin2 +; ASM-NEXT: .word .Lfunc_end0 +; ASM-NEXT: .word .Lfunc_end1 +; ASM-NEXT: .word .Lfunc_end2 + + +; OBJ: Section ({{.*}}) .rela.debug_addr { +; OBJ-NEXT: 0x8 R_RISCV_32 - 0x0 +; OBJ-NEXT: 0xC R_RISCV_32 - 0x0 +; OBJ-NEXT: 0x10 R_RISCV_32 - 0x0 +; OBJ-NEXT: 0x14 R_RISCV_32 - 0x0 +; OBJ-NEXT: 0x18 R_RISCV_32 - 0x0 +; OBJ-NEXT: 0x1C R_RISCV_32 - 0x0 +; OBJ-NEXT: } + + +; DWARFDUMP: DW_TAG_compile_unit +; DWARFDUMP-NEXT: DW_AT_producer ("clang") +; DWARFDUMP-NEXT: DW_AT_language (DW_LANG_C11) +; DWARFDUMP-NEXT: DW_AT_name ("dwarf-riscv-range-list-relocs.c") +; DWARFDUMP-NEXT: DW_AT_str_offsets_base (0x00000008) +; DWARFDUMP-NEXT: DW_AT_stmt_list (0x00000000) +; DWARFDUMP-NEXT: DW_AT_comp_dir (".") +; DWARFDUMP-NEXT: DW_AT_low_pc (0x00000000) +; DWARFDUMP-NEXT: DW_AT_ranges (indexed (0x0) rangelist = 0x00000010 +; DWARFDUMP-NEXT: [0x[[R1_BEGIN:.*]], 0x[[R1_END:.*]]) +; DWARFDUMP-NEXT: [0x[[R2_BEGIN:.*]], 0x[[R2_END:.*]]) +; DWARFDUMP-NEXT: [0x[[R3_BEGIN:.*]], 0x[[R3_END:.*]])) +; DWARFDUMP-NEXT: DW_AT_addr_base (0x00000008) +; DWARFDUMP-NEXT: DW_AT_rnglists_base (0x0000000c) + +; DWARFDUMP: .debug_addr contents +; DWARFDUMP-NEXT: Address table header: length = 0x0000001c, format = DWARF32, version = 0x0005, addr_size = 0x04, seg_size = 0x00 +; DWARFDUMP-NEXT: Addrs: [ +; DWARFDUMP-NEXT: 0x[[R1_BEGIN]] +; DWARFDUMP-NEXT: 0x[[R2_BEGIN]] +; DWARFDUMP-NEXT: 0x[[R3_BEGIN]] +; DWARFDUMP-NEXT: 0x[[R1_END]] +; DWARFDUMP-NEXT: 0x[[R2_END]] +; DWARFDUMP-NEXT: 0x[[R3_END]] +; DWARFDUMP-NEXT: ] + +; DWARFDUMP: .debug_rnglists contents +; DWARFDUMP-NEXT: range list header: length = 0x00000016, format = DWARF32, version = 0x0005, addr_size = 0x04, seg_size = 0x00, offset_entry_count = 0x00000001 +; DWARFDUMP-NEXT: offsets: [ +; DWARFDUMP-NEXT: 0x00000004 +; DWARFDUMP-NEXT: ] +; DWARFDUMP-NEXT: ranges: +; DWARFDUMP-NEXT: [0x[[R1_BEGIN]], 0x[[R1_END]]) +; DWARFDUMP-NEXT: [0x[[R2_BEGIN]], 0x[[R2_END]]) +; DWARFDUMP-NEXT: [0x[[R3_BEGIN]], 0x[[R3_END]]) +; DWARFDUMP-NEXT: + + +; ModuleID = 'dwarf-riscv-range-list-relocs.c' +source_filename = "dwarf-riscv-range-list-relocs.c" +target datalayout = "e-m:e-p:32:32-i64:64-n32-S128" +target triple = "riscv32" + +; Function Attrs: noinline nounwind optnone +define dso_local i32 @baz() #0 !dbg !9 { +entry: + ret i32 0, !dbg !14 +} + +; Function Attrs: noinline nounwind optnone +define dso_local i32 @foo() #0 !dbg !15 { +entry: + %call = call i32 @baz(), !dbg !16 + ret i32 %call, !dbg !17 +} + +; Function Attrs: noinline nounwind optnone +define dso_local i32 @bar() #0 !dbg !18 { +entry: + %call = call i32 @foo(), !dbg !19 + ret i32 %call, !dbg !20 +} + +attributes #0 = { noinline nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit,+a,+c,+m,+relax,-save-restore" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6, !7} +!llvm.ident = !{!8} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "dwarf-riscv-range-list-relocs.c", directory: ".", checksumkind: CSK_MD5, checksum: "b97b465da8a801f3455e96db63ead01f") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 1, !"target-abi", !"ilp32"} +!6 = !{i32 7, !"frame-pointer", i32 2} +!7 = !{i32 1, !"SmallDataLimit", i32 8} +!8 = !{!"clang"} +!9 = distinct !DISubprogram(name: "baz", scope: !1, file: !1, line: 1, type: !10, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13) +!10 = !DISubroutineType(types: !11) +!11 = !{!12} +!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!13 = !{} +!14 = !DILocation(line: 3, column: 3, scope: !9) +!15 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !10, scopeLine: 6, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13) +!16 = !DILocation(line: 6, column: 10, scope: !15) +!17 = !DILocation(line: 6, column: 3, scope: !15) +!18 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 7, type: !10, scopeLine: 9, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13) +!19 = !DILocation(line: 9, column: 10, scope: !18) +!20 = !DILocation(line: 9, column: 3, scope: !18)