forked from OSchip/llvm-project
[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:
parent
55e2d2060a
commit
ad1f5457d2
|
@ -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'
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue