[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
This commit is contained in:
Derek Schuff 2021-06-02 14:37:22 -07:00
parent 55e2d2060a
commit ad1f5457d2
7 changed files with 164 additions and 56 deletions

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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<const MCSectionWasm &>(RelEntry.Symbol->getSection());
return Section.getSectionOffset() + RelEntry.Addend;

View File

@ -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<MCSymbolRefExpr>(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<MCBinaryExpr>(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<MCUnaryExpr>(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<MCSymbolWasm>(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<const MCSectionWasm *>(
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<const MCSectionWasm *>(
getFixupSection(Fixup.getValue()))) {
getTargetSection(Fixup.getValue()))) {
if (Section->getKind().isText())
return wasm::R_WASM_FUNCTION_OFFSET_I64;
else if (!Section->isWasmData())

View File

@ -0,0 +1,67 @@
; RUN: llc -filetype=obj %s -o - | llvm-readobj -r - | FileCheck %s
; Test for PR50408. Compiled from:
; char a();
; template <typename, char b()>
; void f() { b(); }
; void g() { f<char, a>(); }
; 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<char, &a>", 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)

View File

@ -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