From ad1f5457d2d89efa49a722404a5f0b744b7a64d1 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Wed, 2 Jun 2021 14:37:22 -0700 Subject: [PATCH] [WebAssembly] Generate R_WASM_FUNCTION_OFFSET relocs in debuginfo sections Debug info sections need R_WASM_FUNCTION_OFFSET_I32 relocs (with FK_Data_4 fixup kinds) to refer to functions (instead of R_WASM_TABLE_INDEX as is used in data sections). Usually this is done in a convoluted way, with unnamed temp data symbols which target the start of the function, in which case WasmObjectWriter::recordRelocation converts it to use the section symbol instead. However in some cases the function can actually be undefined; in this case the dwarf generator uses the function symbol (a named undefined function symbol) instead. In that case the section-symbol transform doesn't work and we need to generate the correct reloc type a different way. In this change WebAssemblyWasmObjectWriter::getRelocType takes the fixup section type into account to choose the correct reloc type. Fixes PR50408 Differential Revision: https://reviews.llvm.org/D103557 --- lld/test/wasm/debuginfo-relocs.s | 23 -------- lld/test/wasm/map-file.s | 38 ++++++------ llvm/include/llvm/MC/MCWasmObjectWriter.h | 2 + llvm/lib/MC/WasmObjectWriter.cpp | 17 ++++-- .../MCTargetDesc/WebAssemblyWasmObjectWriter.cpp | 30 ++++++---- llvm/test/MC/WebAssembly/debug-template-param.ll | 67 ++++++++++++++++++++++ llvm/test/MC/WebAssembly/debuginfo-relocs.s | 43 ++++++++++++++ 7 files changed, 164 insertions(+), 56 deletions(-) delete mode 100644 lld/test/wasm/debuginfo-relocs.s create mode 100644 llvm/test/MC/WebAssembly/debug-template-param.ll create mode 100644 llvm/test/MC/WebAssembly/debuginfo-relocs.s diff --git a/lld/test/wasm/debuginfo-relocs.s b/lld/test/wasm/debuginfo-relocs.s deleted file mode 100644 index bece55f..0000000 --- a/lld/test/wasm/debuginfo-relocs.s +++ /dev/null @@ -1,23 +0,0 @@ -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s -# RUN: wasm-ld %t.o -o %t.wasm -# RUN: obj2yaml %t.wasm | FileCheck %s - -bar: - .functype bar () -> () - end_function - - .globl _start -_start: - .functype _start () -> () - call bar - end_function - - .section .debug_info,"",@ - .int32 bar - -# Even though `bar` is live in the final binary it doesn't have a table entry -# since its not address taken in the code. In this case any relocations in the -# debug sections see a address of zero. - -# CHECK: Name: .debug_info -# CHECK-NEXT: Payload: '00000000' diff --git a/lld/test/wasm/map-file.s b/lld/test/wasm/map-file.s index a1964fb..1aae7a7 100644 --- a/lld/test/wasm/map-file.s +++ b/lld/test/wasm/map-file.s @@ -29,8 +29,9 @@ _start: .section .data.somedata,"",@ somedata: - .int32 123 -.size somedata, 4 + .int32 123 + .int32 bar +.size somedata, 8 .section .bss.somezeroes,"",@ somezeroes: @@ -50,22 +51,23 @@ somezeroes: # CHECK-NEXT: 0 0 0 __stack_pointer # CHECK-NEXT: 1 0 0 wasm_global # CHECK-NEXT: - 37 15 EXPORT -# CHECK-NEXT: - 4c 2d CODE -# CHECK-NEXT: - 4d 10 {{.*}}{{/|\\}}map-file.s.tmp1.o:(bar) -# CHECK-NEXT: - 4d 10 bar -# CHECK-NEXT: - 5d b {{.*}}{{/|\\}}map-file.s.tmp1.o:(write_global) -# CHECK-NEXT: - 5d b write_global -# CHECK-NEXT: - 68 f {{.*}}{{/|\\}}map-file.s.tmp1.o:(_start) -# CHECK-NEXT: - 68 f _start -# CHECK-NEXT: - 79 d DATA -# CHECK-NEXT: 400 7a 4 .data -# CHECK-NEXT: 400 80 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.data.somedata) -# CHECK-NEXT: 400 80 4 somedata -# CHECK-NEXT: 404 79 4 .bss -# CHECK-NEXT: 404 0 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.bss.somezeroes) -# CHECK-NEXT: 404 0 4 somezeroes -# CHECK-NEXT: - 86 12 CUSTOM(.debug_info) -# CHECK-NEXT: - 98 50 CUSTOM(name) +# CHECK-NEXT: - 4c 9 ELEM +# CHECK-NEXT: - 55 2d CODE +# CHECK-NEXT: - 56 10 {{.*}}{{/|\\}}map-file.s.tmp1.o:(bar) +# CHECK-NEXT: - 56 10 bar +# CHECK-NEXT: - 66 b {{.*}}{{/|\\}}map-file.s.tmp1.o:(write_global) +# CHECK-NEXT: - 66 b write_global +# CHECK-NEXT: - 71 f {{.*}}{{/|\\}}map-file.s.tmp1.o:(_start) +# CHECK-NEXT: - 71 f _start +# CHECK-NEXT: - 82 11 DATA +# CHECK-NEXT: 400 83 8 .data +# CHECK-NEXT: 400 89 8 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.data.somedata) +# CHECK-NEXT: 400 89 8 somedata +# CHECK-NEXT: 408 82 4 .bss +# CHECK-NEXT: 408 0 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.bss.somezeroes) +# CHECK-NEXT: 408 0 4 somezeroes +# CHECK-NEXT: - 93 12 CUSTOM(.debug_info) +# CHECK-NEXT: - a5 50 CUSTOM(name) # RUN: not wasm-ld %t1.o -o /dev/null -Map=/ 2>&1 \ # RUN: | FileCheck -check-prefix=FAIL %s diff --git a/llvm/include/llvm/MC/MCWasmObjectWriter.h b/llvm/include/llvm/MC/MCWasmObjectWriter.h index 4c75ea1..3d5b0940 100644 --- a/llvm/include/llvm/MC/MCWasmObjectWriter.h +++ b/llvm/include/llvm/MC/MCWasmObjectWriter.h @@ -15,6 +15,7 @@ namespace llvm { class MCFixup; +class MCSectionWasm; class MCValue; class raw_pwrite_stream; @@ -34,6 +35,7 @@ public: } virtual unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup, + const MCSectionWasm &FixupSection, bool IsLocRel) const = 0; /// \name Accessors diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp index b86604d..0dc5c91 100644 --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -498,14 +498,21 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, // be negative and don't wrap. FixedValue = 0; - unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup, IsLocRel); + unsigned Type = + TargetObjectWriter->getRelocType(Target, Fixup, FixupSection, IsLocRel); // Absolute offset within a section or a function. // Currently only supported for for metadata sections. // See: test/MC/WebAssembly/blockaddress.ll - if (Type == wasm::R_WASM_FUNCTION_OFFSET_I32 || - Type == wasm::R_WASM_FUNCTION_OFFSET_I64 || - Type == wasm::R_WASM_SECTION_OFFSET_I32) { + if ((Type == wasm::R_WASM_FUNCTION_OFFSET_I32 || + Type == wasm::R_WASM_FUNCTION_OFFSET_I64 || + Type == wasm::R_WASM_SECTION_OFFSET_I32) && + SymA->isDefined()) { + // SymA can be a temp data symbol that represents a function (in which case + // it needs to be replaced by the section symbol), [XXX and it apparently + // later gets changed again to a func symbol?] or it can be a real + // function symbol, in which case it can be left as-is. + if (!FixupSection.getKind().isMetadata()) report_fatal_error("relocations for function or section offsets are " "only supported in metadata sections"); @@ -620,6 +627,8 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry, case wasm::R_WASM_FUNCTION_OFFSET_I32: case wasm::R_WASM_FUNCTION_OFFSET_I64: case wasm::R_WASM_SECTION_OFFSET_I32: { + if (!RelEntry.Symbol->isDefined()) + return 0; const auto &Section = static_cast(RelEntry.Symbol->getSection()); return Section.getSectionOffset() + RelEntry.Addend; diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp index 48e8654..f67fab9 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -35,6 +35,7 @@ public: private: unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup, + const MCSectionWasm &FixupSection, bool IsLocRel) const override; }; } // end anonymous namespace @@ -43,7 +44,7 @@ WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten) : MCWasmObjectTargetWriter(Is64Bit, IsEmscripten) {} -static const MCSection *getFixupSection(const MCExpr *Expr) { +static const MCSection *getTargetSection(const MCExpr *Expr) { if (auto SyExp = dyn_cast(Expr)) { if (SyExp->getSymbol().isInSection()) return &SyExp->getSymbol().getSection(); @@ -51,20 +52,20 @@ static const MCSection *getFixupSection(const MCExpr *Expr) { } if (auto BinOp = dyn_cast(Expr)) { - auto SectionLHS = getFixupSection(BinOp->getLHS()); - auto SectionRHS = getFixupSection(BinOp->getRHS()); + auto SectionLHS = getTargetSection(BinOp->getLHS()); + auto SectionRHS = getTargetSection(BinOp->getRHS()); return SectionLHS == SectionRHS ? nullptr : SectionLHS; } if (auto UnOp = dyn_cast(Expr)) - return getFixupSection(UnOp->getSubExpr()); + return getTargetSection(UnOp->getSubExpr()); return nullptr; } -unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, - const MCFixup &Fixup, - bool IsLocRel) const { +unsigned WebAssemblyWasmObjectWriter::getRelocType( + const MCValue &Target, const MCFixup &Fixup, + const MCSectionWasm &FixupSection, bool IsLocRel) const { const MCSymbolRefExpr *RefA = Target.getSymA(); assert(RefA); auto& SymA = cast(RefA->getSymbol()); @@ -114,12 +115,16 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, assert(SymA.isData()); return wasm::R_WASM_MEMORY_ADDR_LEB64; case FK_Data_4: - if (SymA.isFunction()) + if (SymA.isFunction()) { + if (FixupSection.getKind().isMetadata()) + return wasm::R_WASM_FUNCTION_OFFSET_I32; + assert(FixupSection.isWasmData()); return wasm::R_WASM_TABLE_INDEX_I32; + } if (SymA.isGlobal()) return wasm::R_WASM_GLOBAL_INDEX_I32; if (auto Section = static_cast( - getFixupSection(Fixup.getValue()))) { + getTargetSection(Fixup.getValue()))) { if (Section->getKind().isText()) return wasm::R_WASM_FUNCTION_OFFSET_I32; else if (!Section->isWasmData()) @@ -128,12 +133,15 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, return IsLocRel ? wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 : wasm::R_WASM_MEMORY_ADDR_I32; case FK_Data_8: - if (SymA.isFunction()) + if (SymA.isFunction()) { + if (FixupSection.getKind().isMetadata()) + return wasm::R_WASM_FUNCTION_OFFSET_I64; return wasm::R_WASM_TABLE_INDEX_I64; + } if (SymA.isGlobal()) llvm_unreachable("unimplemented R_WASM_GLOBAL_INDEX_I64"); if (auto Section = static_cast( - getFixupSection(Fixup.getValue()))) { + getTargetSection(Fixup.getValue()))) { if (Section->getKind().isText()) return wasm::R_WASM_FUNCTION_OFFSET_I64; else if (!Section->isWasmData()) diff --git a/llvm/test/MC/WebAssembly/debug-template-param.ll b/llvm/test/MC/WebAssembly/debug-template-param.ll new file mode 100644 index 0000000..6f17f1c --- /dev/null +++ b/llvm/test/MC/WebAssembly/debug-template-param.ll @@ -0,0 +1,67 @@ +; RUN: llc -filetype=obj %s -o - | llvm-readobj -r - | FileCheck %s + +; Test for PR50408. Compiled from: +; char a(); +; template +; void f() { b(); } +; void g() { f(); } + +; CHECK: Section (10) .debug_addr +; CHECK-NEXT: 0x8 R_WASM_FUNCTION_OFFSET_I32 _Z1gv 0 +; CHECK-NEXT: 0xC R_WASM_FUNCTION_OFFSET_I32 _Z1fIcXadL_Z1avEEEvv 0 +; ensure that the reloc type is correct for _Z1av which is undefined +; CHECK-NEXT: 0x10 R_WASM_FUNCTION_OFFSET_I32 _Z1av 0 +; CHECK-NEXT: } + +; ModuleID = 'PR50408.cc' +source_filename = "PR50408.cc" +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1" +target triple = "wasm32-unknown-emscripten" + +$_Z1fIcXadL_Z1avEEEvv = comdat any + +; Function Attrs: noinline optnone mustprogress +define hidden void @_Z1gv() #0 !dbg !7 { +entry: + call void @_Z1fIcXadL_Z1avEEEvv(), !dbg !10 + ret void, !dbg !11 +} + +; Function Attrs: noinline optnone mustprogress +define linkonce_odr hidden void @_Z1fIcXadL_Z1avEEEvv() #0 comdat !dbg !12 { +entry: + %call = call signext i8 @_Z1av(), !dbg !20 + ret void, !dbg !21 +} + +declare signext i8 @_Z1av() #1 + +attributes #0 = { noinline optnone mustprogress "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" } +attributes #1 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 5027637fa1d409e3ca78dab60dc2e2db6c62c175)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "PR50408.cc", directory: "/s/emr/emscripten-releases/localtests", checksumkind: CSK_MD5, checksum: "285a5682ae46dbbe90ccfb84cdef66c7") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 5} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 5027637fa1d409e3ca78dab60dc2e2db6c62c175)"} +!7 = distinct !DISubprogram(name: "g", linkageName: "_Z1gv", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !DILocation(line: 5, column: 12, scope: !7) +!11 = !DILocation(line: 5, column: 26, scope: !7) +!12 = distinct !DISubprogram(name: "f", linkageName: "_Z1fIcXadL_Z1avEEEvv", scope: !1, file: !1, line: 4, type: !8, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, templateParams: !13, retainedNodes: !2) +!13 = !{!14, !16} +!14 = !DITemplateTypeParameter(type: !15) +!15 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!16 = !DITemplateValueParameter(name: "b", type: !17, value: i8 ()* @_Z1av) +!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 32) +!18 = !DISubroutineType(types: !19) +!19 = !{!15} +!20 = !DILocation(line: 4, column: 12, scope: !12) +!21 = !DILocation(line: 4, column: 17, scope: !12) diff --git a/llvm/test/MC/WebAssembly/debuginfo-relocs.s b/llvm/test/MC/WebAssembly/debuginfo-relocs.s new file mode 100644 index 0000000..e0343c9 --- /dev/null +++ b/llvm/test/MC/WebAssembly/debuginfo-relocs.s @@ -0,0 +1,43 @@ +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s +# RUN: obj2yaml %t.o | FileCheck %s + +.functype undef () -> () + +bar: + .functype bar () -> () + end_function + + .globl _start +_start: + .functype _start () -> () + call bar + end_function + +.section .debug_int,"",@ +.Ld: + .int32 1 +.size .Ld, 4 + +.section .debug_info,"",@ + .int32 bar + .int32 undef + .int32 .Ld + +## Test that relocations in metadata sections against both defined and undef +## function symbols get R_WASM_FUNCTION_OFFSET relocations, and relocs against +## data symbols get R_WASM_SECTION_OFFSET relocs. +# CHECK: - Type: CUSTOM +# CHECK-NEXT: Name: .debug_int +# CHECK: - Type: CUSTOM +# CHECK-NEXT: Relocations: +# CHECK-NEXT: - Type: R_WASM_FUNCTION_OFFSET_I32 +# CHECK-NEXT: Index: 0 +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: - Type: R_WASM_FUNCTION_OFFSET_I32 +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Offset: 0x4 +# CHECK-NEXT: - Type: R_WASM_SECTION_OFFSET_I32 +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Offset: 0x8 +# CHECK-NEXT: Name: .debug_info + -- 2.7.4