Skip to content

Commit ad1f545

Browse files
committed
[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
1 parent 55e2d20 commit ad1f545

File tree

7 files changed

+164
-56
lines changed

7 files changed

+164
-56
lines changed

lld/test/wasm/debuginfo-relocs.s

-23
This file was deleted.

lld/test/wasm/map-file.s

+20-18
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ _start:
2929

3030
.section .data.somedata,"",@
3131
somedata:
32-
.int32 123
33-
.size somedata, 4
32+
.int32 123
33+
.int32 bar
34+
.size somedata, 8
3435

3536
.section .bss.somezeroes,"",@
3637
somezeroes:
@@ -50,22 +51,23 @@ somezeroes:
5051
# CHECK-NEXT: 0 0 0 __stack_pointer
5152
# CHECK-NEXT: 1 0 0 wasm_global
5253
# CHECK-NEXT: - 37 15 EXPORT
53-
# CHECK-NEXT: - 4c 2d CODE
54-
# CHECK-NEXT: - 4d 10 {{.*}}{{/|\\}}map-file.s.tmp1.o:(bar)
55-
# CHECK-NEXT: - 4d 10 bar
56-
# CHECK-NEXT: - 5d b {{.*}}{{/|\\}}map-file.s.tmp1.o:(write_global)
57-
# CHECK-NEXT: - 5d b write_global
58-
# CHECK-NEXT: - 68 f {{.*}}{{/|\\}}map-file.s.tmp1.o:(_start)
59-
# CHECK-NEXT: - 68 f _start
60-
# CHECK-NEXT: - 79 d DATA
61-
# CHECK-NEXT: 400 7a 4 .data
62-
# CHECK-NEXT: 400 80 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.data.somedata)
63-
# CHECK-NEXT: 400 80 4 somedata
64-
# CHECK-NEXT: 404 79 4 .bss
65-
# CHECK-NEXT: 404 0 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.bss.somezeroes)
66-
# CHECK-NEXT: 404 0 4 somezeroes
67-
# CHECK-NEXT: - 86 12 CUSTOM(.debug_info)
68-
# CHECK-NEXT: - 98 50 CUSTOM(name)
54+
# CHECK-NEXT: - 4c 9 ELEM
55+
# CHECK-NEXT: - 55 2d CODE
56+
# CHECK-NEXT: - 56 10 {{.*}}{{/|\\}}map-file.s.tmp1.o:(bar)
57+
# CHECK-NEXT: - 56 10 bar
58+
# CHECK-NEXT: - 66 b {{.*}}{{/|\\}}map-file.s.tmp1.o:(write_global)
59+
# CHECK-NEXT: - 66 b write_global
60+
# CHECK-NEXT: - 71 f {{.*}}{{/|\\}}map-file.s.tmp1.o:(_start)
61+
# CHECK-NEXT: - 71 f _start
62+
# CHECK-NEXT: - 82 11 DATA
63+
# CHECK-NEXT: 400 83 8 .data
64+
# CHECK-NEXT: 400 89 8 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.data.somedata)
65+
# CHECK-NEXT: 400 89 8 somedata
66+
# CHECK-NEXT: 408 82 4 .bss
67+
# CHECK-NEXT: 408 0 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.bss.somezeroes)
68+
# CHECK-NEXT: 408 0 4 somezeroes
69+
# CHECK-NEXT: - 93 12 CUSTOM(.debug_info)
70+
# CHECK-NEXT: - a5 50 CUSTOM(name)
6971

7072
# RUN: not wasm-ld %t1.o -o /dev/null -Map=/ 2>&1 \
7173
# RUN: | FileCheck -check-prefix=FAIL %s

llvm/include/llvm/MC/MCWasmObjectWriter.h

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
namespace llvm {
1616

1717
class MCFixup;
18+
class MCSectionWasm;
1819
class MCValue;
1920
class raw_pwrite_stream;
2021

@@ -34,6 +35,7 @@ class MCWasmObjectTargetWriter : public MCObjectTargetWriter {
3435
}
3536

3637
virtual unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup,
38+
const MCSectionWasm &FixupSection,
3739
bool IsLocRel) const = 0;
3840

3941
/// \name Accessors

llvm/lib/MC/WasmObjectWriter.cpp

+13-4
Original file line numberDiff line numberDiff line change
@@ -498,14 +498,21 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
498498
// be negative and don't wrap.
499499
FixedValue = 0;
500500

501-
unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup, IsLocRel);
501+
unsigned Type =
502+
TargetObjectWriter->getRelocType(Target, Fixup, FixupSection, IsLocRel);
502503

503504
// Absolute offset within a section or a function.
504505
// Currently only supported for for metadata sections.
505506
// See: test/MC/WebAssembly/blockaddress.ll
506-
if (Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
507-
Type == wasm::R_WASM_FUNCTION_OFFSET_I64 ||
508-
Type == wasm::R_WASM_SECTION_OFFSET_I32) {
507+
if ((Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
508+
Type == wasm::R_WASM_FUNCTION_OFFSET_I64 ||
509+
Type == wasm::R_WASM_SECTION_OFFSET_I32) &&
510+
SymA->isDefined()) {
511+
// SymA can be a temp data symbol that represents a function (in which case
512+
// it needs to be replaced by the section symbol), [XXX and it apparently
513+
// later gets changed again to a func symbol?] or it can be a real
514+
// function symbol, in which case it can be left as-is.
515+
509516
if (!FixupSection.getKind().isMetadata())
510517
report_fatal_error("relocations for function or section offsets are "
511518
"only supported in metadata sections");
@@ -620,6 +627,8 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry,
620627
case wasm::R_WASM_FUNCTION_OFFSET_I32:
621628
case wasm::R_WASM_FUNCTION_OFFSET_I64:
622629
case wasm::R_WASM_SECTION_OFFSET_I32: {
630+
if (!RelEntry.Symbol->isDefined())
631+
return 0;
623632
const auto &Section =
624633
static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection());
625634
return Section.getSectionOffset() + RelEntry.Addend;

llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp

+19-11
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter {
3535

3636
private:
3737
unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup,
38+
const MCSectionWasm &FixupSection,
3839
bool IsLocRel) const override;
3940
};
4041
} // end anonymous namespace
@@ -43,28 +44,28 @@ WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit,
4344
bool IsEmscripten)
4445
: MCWasmObjectTargetWriter(Is64Bit, IsEmscripten) {}
4546

46-
static const MCSection *getFixupSection(const MCExpr *Expr) {
47+
static const MCSection *getTargetSection(const MCExpr *Expr) {
4748
if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr)) {
4849
if (SyExp->getSymbol().isInSection())
4950
return &SyExp->getSymbol().getSection();
5051
return nullptr;
5152
}
5253

5354
if (auto BinOp = dyn_cast<MCBinaryExpr>(Expr)) {
54-
auto SectionLHS = getFixupSection(BinOp->getLHS());
55-
auto SectionRHS = getFixupSection(BinOp->getRHS());
55+
auto SectionLHS = getTargetSection(BinOp->getLHS());
56+
auto SectionRHS = getTargetSection(BinOp->getRHS());
5657
return SectionLHS == SectionRHS ? nullptr : SectionLHS;
5758
}
5859

5960
if (auto UnOp = dyn_cast<MCUnaryExpr>(Expr))
60-
return getFixupSection(UnOp->getSubExpr());
61+
return getTargetSection(UnOp->getSubExpr());
6162

6263
return nullptr;
6364
}
6465

65-
unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
66-
const MCFixup &Fixup,
67-
bool IsLocRel) const {
66+
unsigned WebAssemblyWasmObjectWriter::getRelocType(
67+
const MCValue &Target, const MCFixup &Fixup,
68+
const MCSectionWasm &FixupSection, bool IsLocRel) const {
6869
const MCSymbolRefExpr *RefA = Target.getSymA();
6970
assert(RefA);
7071
auto& SymA = cast<MCSymbolWasm>(RefA->getSymbol());
@@ -114,12 +115,16 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
114115
assert(SymA.isData());
115116
return wasm::R_WASM_MEMORY_ADDR_LEB64;
116117
case FK_Data_4:
117-
if (SymA.isFunction())
118+
if (SymA.isFunction()) {
119+
if (FixupSection.getKind().isMetadata())
120+
return wasm::R_WASM_FUNCTION_OFFSET_I32;
121+
assert(FixupSection.isWasmData());
118122
return wasm::R_WASM_TABLE_INDEX_I32;
123+
}
119124
if (SymA.isGlobal())
120125
return wasm::R_WASM_GLOBAL_INDEX_I32;
121126
if (auto Section = static_cast<const MCSectionWasm *>(
122-
getFixupSection(Fixup.getValue()))) {
127+
getTargetSection(Fixup.getValue()))) {
123128
if (Section->getKind().isText())
124129
return wasm::R_WASM_FUNCTION_OFFSET_I32;
125130
else if (!Section->isWasmData())
@@ -128,12 +133,15 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
128133
return IsLocRel ? wasm::R_WASM_MEMORY_ADDR_LOCREL_I32
129134
: wasm::R_WASM_MEMORY_ADDR_I32;
130135
case FK_Data_8:
131-
if (SymA.isFunction())
136+
if (SymA.isFunction()) {
137+
if (FixupSection.getKind().isMetadata())
138+
return wasm::R_WASM_FUNCTION_OFFSET_I64;
132139
return wasm::R_WASM_TABLE_INDEX_I64;
140+
}
133141
if (SymA.isGlobal())
134142
llvm_unreachable("unimplemented R_WASM_GLOBAL_INDEX_I64");
135143
if (auto Section = static_cast<const MCSectionWasm *>(
136-
getFixupSection(Fixup.getValue()))) {
144+
getTargetSection(Fixup.getValue()))) {
137145
if (Section->getKind().isText())
138146
return wasm::R_WASM_FUNCTION_OFFSET_I64;
139147
else if (!Section->isWasmData())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
; RUN: llc -filetype=obj %s -o - | llvm-readobj -r - | FileCheck %s
2+
3+
; Test for PR50408. Compiled from:
4+
; char a();
5+
; template <typename, char b()>
6+
; void f() { b(); }
7+
; void g() { f<char, a>(); }
8+
9+
; CHECK: Section (10) .debug_addr
10+
; CHECK-NEXT: 0x8 R_WASM_FUNCTION_OFFSET_I32 _Z1gv 0
11+
; CHECK-NEXT: 0xC R_WASM_FUNCTION_OFFSET_I32 _Z1fIcXadL_Z1avEEEvv 0
12+
; ensure that the reloc type is correct for _Z1av which is undefined
13+
; CHECK-NEXT: 0x10 R_WASM_FUNCTION_OFFSET_I32 _Z1av 0
14+
; CHECK-NEXT: }
15+
16+
; ModuleID = 'PR50408.cc'
17+
source_filename = "PR50408.cc"
18+
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1"
19+
target triple = "wasm32-unknown-emscripten"
20+
21+
$_Z1fIcXadL_Z1avEEEvv = comdat any
22+
23+
; Function Attrs: noinline optnone mustprogress
24+
define hidden void @_Z1gv() #0 !dbg !7 {
25+
entry:
26+
call void @_Z1fIcXadL_Z1avEEEvv(), !dbg !10
27+
ret void, !dbg !11
28+
}
29+
30+
; Function Attrs: noinline optnone mustprogress
31+
define linkonce_odr hidden void @_Z1fIcXadL_Z1avEEEvv() #0 comdat !dbg !12 {
32+
entry:
33+
%call = call signext i8 @_Z1av(), !dbg !20
34+
ret void, !dbg !21
35+
}
36+
37+
declare signext i8 @_Z1av() #1
38+
39+
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" }
40+
attributes #1 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" }
41+
42+
!llvm.dbg.cu = !{!0}
43+
!llvm.module.flags = !{!3, !4, !5}
44+
!llvm.ident = !{!6}
45+
46+
!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)
47+
!1 = !DIFile(filename: "PR50408.cc", directory: "/s/emr/emscripten-releases/localtests", checksumkind: CSK_MD5, checksum: "285a5682ae46dbbe90ccfb84cdef66c7")
48+
!2 = !{}
49+
!3 = !{i32 7, !"Dwarf Version", i32 5}
50+
!4 = !{i32 2, !"Debug Info Version", i32 3}
51+
!5 = !{i32 1, !"wchar_size", i32 4}
52+
!6 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 5027637fa1d409e3ca78dab60dc2e2db6c62c175)"}
53+
!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)
54+
!8 = !DISubroutineType(types: !9)
55+
!9 = !{null}
56+
!10 = !DILocation(line: 5, column: 12, scope: !7)
57+
!11 = !DILocation(line: 5, column: 26, scope: !7)
58+
!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)
59+
!13 = !{!14, !16}
60+
!14 = !DITemplateTypeParameter(type: !15)
61+
!15 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
62+
!16 = !DITemplateValueParameter(name: "b", type: !17, value: i8 ()* @_Z1av)
63+
!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 32)
64+
!18 = !DISubroutineType(types: !19)
65+
!19 = !{!15}
66+
!20 = !DILocation(line: 4, column: 12, scope: !12)
67+
!21 = !DILocation(line: 4, column: 17, scope: !12)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
2+
# RUN: obj2yaml %t.o | FileCheck %s
3+
4+
.functype undef () -> ()
5+
6+
bar:
7+
.functype bar () -> ()
8+
end_function
9+
10+
.globl _start
11+
_start:
12+
.functype _start () -> ()
13+
call bar
14+
end_function
15+
16+
.section .debug_int,"",@
17+
.Ld:
18+
.int32 1
19+
.size .Ld, 4
20+
21+
.section .debug_info,"",@
22+
.int32 bar
23+
.int32 undef
24+
.int32 .Ld
25+
26+
## Test that relocations in metadata sections against both defined and undef
27+
## function symbols get R_WASM_FUNCTION_OFFSET relocations, and relocs against
28+
## data symbols get R_WASM_SECTION_OFFSET relocs.
29+
# CHECK: - Type: CUSTOM
30+
# CHECK-NEXT: Name: .debug_int
31+
# CHECK: - Type: CUSTOM
32+
# CHECK-NEXT: Relocations:
33+
# CHECK-NEXT: - Type: R_WASM_FUNCTION_OFFSET_I32
34+
# CHECK-NEXT: Index: 0
35+
# CHECK-NEXT: Offset: 0x0
36+
# CHECK-NEXT: - Type: R_WASM_FUNCTION_OFFSET_I32
37+
# CHECK-NEXT: Index: 3
38+
# CHECK-NEXT: Offset: 0x4
39+
# CHECK-NEXT: - Type: R_WASM_SECTION_OFFSET_I32
40+
# CHECK-NEXT: Index: 2
41+
# CHECK-NEXT: Offset: 0x8
42+
# CHECK-NEXT: Name: .debug_info
43+

0 commit comments

Comments
 (0)