[WebAssembly] Add support for debug (DWARF) sections
Specifically add support for custom sections that contain relocations, and for the two new relocation types needed by DWARF sections. See: https://reviews.llvm.org/D44184 Patch by Yury Delendik! Differential Revision: https://reviews.llvm.org/D44184 llvm-svn: 331566
This commit is contained in:
parent
e0fb481cc5
commit
d177ab2a5f
|
@ -0,0 +1,68 @@
|
|||
; ModuleID = 'hi.c'
|
||||
source_filename = "hi.c"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-unknown-wasm"
|
||||
|
||||
; // hi.c:
|
||||
; extern void foo(int);
|
||||
;
|
||||
; int test(int t) {
|
||||
; return t * t;
|
||||
; }
|
||||
;
|
||||
; int _start() {
|
||||
; foo(test(10));
|
||||
; return 0;
|
||||
; }
|
||||
|
||||
; Function Attrs: nounwind readnone
|
||||
define hidden i32 @test(i32 %t) local_unnamed_addr #0 !dbg !7 {
|
||||
entry:
|
||||
call void @llvm.dbg.value(metadata i32 %t, metadata !12, metadata !DIExpression()), !dbg !13
|
||||
%mul = mul nsw i32 %t, %t, !dbg !14
|
||||
ret i32 %mul, !dbg !15
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @_start() local_unnamed_addr #1 !dbg !16 {
|
||||
entry:
|
||||
tail call void @foo(i32 100) #4, !dbg !19
|
||||
ret i32 0, !dbg !20
|
||||
}
|
||||
|
||||
declare void @foo(i32) local_unnamed_addr #2
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata) #3
|
||||
|
||||
attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #3 = { nounwind readnone speculatable }
|
||||
attributes #4 = { nounwind }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5}
|
||||
!llvm.ident = !{!6}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 (trunk 331321)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "hi.c", directory: "/Users/yury/llvmwasm")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!5 = !{i32 1, !"wchar_size", i32 4}
|
||||
!6 = !{!"clang version 7.0.0 (trunk 331321)"}
|
||||
!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !11)
|
||||
!8 = !DISubroutineType(types: !9)
|
||||
!9 = !{!10, !10}
|
||||
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!11 = !{!12}
|
||||
!12 = !DILocalVariable(name: "t", arg: 1, scope: !7, file: !1, line: 3, type: !10)
|
||||
!13 = !DILocation(line: 3, column: 14, scope: !7)
|
||||
!14 = !DILocation(line: 4, column: 12, scope: !7)
|
||||
!15 = !DILocation(line: 4, column: 3, scope: !7)
|
||||
!16 = distinct !DISubprogram(name: "_start", scope: !1, file: !1, line: 7, type: !17, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: true, unit: !0, variables: !2)
|
||||
!17 = !DISubroutineType(types: !18)
|
||||
!18 = !{!10}
|
||||
!19 = !DILocation(line: 8, column: 3, scope: !16)
|
||||
!20 = !DILocation(line: 9, column: 3, scope: !16)
|
|
@ -0,0 +1,64 @@
|
|||
; ModuleID = 'hi_foo.c'
|
||||
source_filename = "hi_foo.c"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-unknown-wasm"
|
||||
|
||||
; // hi_foo.c:
|
||||
; int y[2] = {23, 41};
|
||||
;
|
||||
; void foo(int p) {
|
||||
; y[p & 1]++;
|
||||
; }
|
||||
|
||||
@y = hidden local_unnamed_addr global [2 x i32] [i32 23, i32 41], align 4, !dbg !0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @foo(i32 %p) local_unnamed_addr #0 !dbg !14 {
|
||||
entry:
|
||||
call void @llvm.dbg.value(metadata i32 %p, metadata !18, metadata !DIExpression()), !dbg !19
|
||||
%and = and i32 %p, 1, !dbg !20
|
||||
%arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* @y, i32 0, i32 %and, !dbg !21
|
||||
%0 = load i32, i32* %arrayidx, align 4, !dbg !22, !tbaa !23
|
||||
%inc = add nsw i32 %0, 1, !dbg !22
|
||||
store i32 %inc, i32* %arrayidx, align 4, !dbg !22, !tbaa !23
|
||||
ret void, !dbg !27
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
|
||||
|
||||
attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #1 = { nounwind readnone speculatable }
|
||||
|
||||
!llvm.dbg.cu = !{!2}
|
||||
!llvm.module.flags = !{!10, !11, !12}
|
||||
!llvm.ident = !{!13}
|
||||
|
||||
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
|
||||
!1 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true)
|
||||
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 7.0.0 (trunk 331321)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
|
||||
!3 = !DIFile(filename: "hi_foo.c", directory: "/Users/yury/llvmwasm")
|
||||
!4 = !{}
|
||||
!5 = !{!0}
|
||||
!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 64, elements: !8)
|
||||
!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!8 = !{!9}
|
||||
!9 = !DISubrange(count: 2)
|
||||
!10 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!11 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!12 = !{i32 1, !"wchar_size", i32 4}
|
||||
!13 = !{!"clang version 7.0.0 (trunk 331321)"}
|
||||
!14 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 3, type: !15, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !2, variables: !17)
|
||||
!15 = !DISubroutineType(types: !16)
|
||||
!16 = !{null, !7}
|
||||
!17 = !{!18}
|
||||
!18 = !DILocalVariable(name: "p", arg: 1, scope: !14, file: !3, line: 3, type: !7)
|
||||
!19 = !DILocation(line: 3, column: 14, scope: !14)
|
||||
!20 = !DILocation(line: 4, column: 7, scope: !14)
|
||||
!21 = !DILocation(line: 4, column: 3, scope: !14)
|
||||
!22 = !DILocation(line: 4, column: 11, scope: !14)
|
||||
!23 = !{!24, !24, i64 0}
|
||||
!24 = !{!"int", !25, i64 0}
|
||||
!25 = !{!"omnipotent char", !26, i64 0}
|
||||
!26 = !{!"Simple C/C++ TBAA"}
|
||||
!27 = !DILocation(line: 5, column: 1, scope: !14)
|
|
@ -0,0 +1,73 @@
|
|||
RUN: llc -filetype=obj %p/Inputs/debuginfo1.ll -o %t.debuginfo1.o
|
||||
RUN: llc -filetype=obj %p/Inputs/debuginfo2.ll -o %t.debuginfo2.o
|
||||
RUN: wasm-ld -r -o %t.wasm %t.debuginfo1.o %t.debuginfo2.o
|
||||
RUN: llvm-dwarfdump %t.wasm | FileCheck %s
|
||||
|
||||
CHECK: file format WASM
|
||||
|
||||
CHECK: .debug_info contents:
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK-NEXT: DW_AT_producer ("clang version 7.0.0 (trunk 331321)")
|
||||
CHECK-NEXT: DW_AT_language (DW_LANG_C99)
|
||||
CHECK-NEXT: DW_AT_name ("hi.c")
|
||||
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK-NEXT: DW_AT_low_pc
|
||||
CHECK-NEXT: DW_AT_high_pc
|
||||
CHECK-NEXT: DW_AT_name ("test")
|
||||
CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm/hi.c")
|
||||
CHECK-NEXT: DW_AT_decl_line (3)
|
||||
CHECK-NEXT: DW_AT_prototyped (true)
|
||||
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK-NEXT: DW_AT_name ("t")
|
||||
CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm/hi.c")
|
||||
CHECK-NEXT: DW_AT_decl_line (3)
|
||||
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK-NEXT: DW_AT_low_pc
|
||||
CHECK-NEXT: DW_AT_high_pc
|
||||
CHECK-NEXT: DW_AT_name ("_start")
|
||||
CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm/hi.c")
|
||||
CHECK-NEXT: DW_AT_decl_line (7)
|
||||
|
||||
CHECK: DW_TAG_base_type
|
||||
CHECK-NEXT: DW_AT_name ("int")
|
||||
CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
|
||||
CHECK-NEXT: DW_AT_byte_size (0x04)
|
||||
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK-NEXT: DW_AT_producer ("clang version 7.0.0 (trunk 331321)")
|
||||
CHECK-NEXT: DW_AT_language (DW_LANG_C99)
|
||||
CHECK-NEXT: DW_AT_name ("hi_foo.c")
|
||||
|
||||
CHECK: DW_TAG_variable
|
||||
CHECK-NEXT: DW_AT_name ("y")
|
||||
CHECK-NEXT: "int[]"
|
||||
|
||||
CHECK: DW_TAG_array_type
|
||||
|
||||
CHECK: DW_TAG_subrange_type
|
||||
|
||||
CHECK: DW_TAG_base_type
|
||||
CHECK-NEXT: DW_AT_name ("int")
|
||||
CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
|
||||
CHECK-NEXT: DW_AT_byte_size (0x04)
|
||||
|
||||
CHECK: DW_TAG_base_type
|
||||
CHECK-NEXT: DW_AT_name ("__ARRAY_SIZE_TYPE__")
|
||||
CHECK-NEXT: DW_AT_byte_size (0x08)
|
||||
CHECK-NEXT: DW_AT_encoding (DW_ATE_unsigned)
|
||||
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK-NEXT: DW_AT_low_pc
|
||||
CHECK-NEXT: DW_AT_high_pc
|
||||
CHECK-NEXT: DW_AT_name ("foo")
|
||||
CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm/hi_foo.c")
|
||||
CHECK-NEXT: DW_AT_decl_line (3)
|
||||
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK-NEXT: DW_AT_name ("p")
|
||||
CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm/hi_foo.c")
|
||||
CHECK-NEXT: DW_AT_decl_line (3)
|
||||
|
|
@ -89,6 +89,8 @@ void InputChunk::writeTo(uint8_t *Buf) const {
|
|||
break;
|
||||
case R_WEBASSEMBLY_TABLE_INDEX_I32:
|
||||
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
|
||||
case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
|
||||
case R_WEBASSEMBLY_SECTION_OFFSET_I32:
|
||||
ExistingValue = static_cast<uint32_t>(read32le(Loc));
|
||||
write32le(Loc, Value);
|
||||
break;
|
||||
|
@ -124,7 +126,9 @@ void InputChunk::writeRelocations(raw_ostream &OS) const {
|
|||
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
|
||||
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
|
||||
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
|
||||
writeSleb128(OS, Rel.Addend, "reloc addend");
|
||||
case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
|
||||
case R_WEBASSEMBLY_SECTION_OFFSET_I32:
|
||||
writeSleb128(OS, File->calcNewAddend(Rel), "reloc addend");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,6 +130,8 @@ public:
|
|||
StringRef getName() const override { return Function->SymbolName; }
|
||||
StringRef getDebugName() const override { return Function->DebugName; }
|
||||
uint32_t getComdat() const override { return Function->Comdat; }
|
||||
const ArrayRef<uint8_t> getFunctionBody() const { return Function->Body; }
|
||||
uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); }
|
||||
uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); }
|
||||
bool hasFunctionIndex() const { return FunctionIndex.hasValue(); }
|
||||
void setFunctionIndex(uint32_t Index);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "lld/Common/Memory.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/Wasm.h"
|
||||
#include "llvm/Support/LEB128.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#define DEBUG_TYPE "lld"
|
||||
|
@ -42,6 +43,12 @@ Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) {
|
|||
return MBRef;
|
||||
}
|
||||
|
||||
static size_t getFunctionCodeOffset(ArrayRef<uint8_t> FunctionBody) {
|
||||
unsigned Count;
|
||||
llvm::decodeULEB128(FunctionBody.data(), &Count);
|
||||
return Count;
|
||||
}
|
||||
|
||||
void ObjFile::dumpInfo() const {
|
||||
log("info for: " + getName() +
|
||||
"\n Symbols : " + Twine(Symbols.size()) +
|
||||
|
@ -60,6 +67,22 @@ uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const {
|
|||
return Symbols[Reloc.Index]->getOutputSymbolIndex();
|
||||
}
|
||||
|
||||
// Relocations can contain addend for combined sections. This function takes a
|
||||
// relocation and returns updated addend by offset in the output section.
|
||||
uint32_t ObjFile::calcNewAddend(const WasmRelocation &Reloc) const {
|
||||
switch (Reloc.Type) {
|
||||
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
|
||||
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
|
||||
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
|
||||
case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
|
||||
return Reloc.Addend;
|
||||
case R_WEBASSEMBLY_SECTION_OFFSET_I32:
|
||||
return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend;
|
||||
default:
|
||||
llvm_unreachable("unexpected relocation type");
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the value we expect to find at the relocation location.
|
||||
// This is used as a sanity check before applying a relocation to a given
|
||||
// location. It is useful for catching bugs in the compiler and linker.
|
||||
|
@ -80,6 +103,16 @@ uint32_t ObjFile::calcExpectedValue(const WasmRelocation &Reloc) const {
|
|||
return Segment.Data.Offset.Value.Int32 + Sym.Info.DataRef.Offset +
|
||||
Reloc.Addend;
|
||||
}
|
||||
case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
|
||||
if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) {
|
||||
size_t FunctionCodeOffset =
|
||||
getFunctionCodeOffset(Sym->Function->getFunctionBody());
|
||||
return Sym->Function->getFunctionInputOffset() + FunctionCodeOffset +
|
||||
Reloc.Addend;
|
||||
}
|
||||
return 0;
|
||||
case R_WEBASSEMBLY_SECTION_OFFSET_I32:
|
||||
return Reloc.Addend;
|
||||
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
|
||||
return Reloc.Index;
|
||||
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
|
||||
|
@ -110,6 +143,15 @@ uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const {
|
|||
return getFunctionSymbol(Reloc.Index)->getFunctionIndex();
|
||||
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
|
||||
return getGlobalSymbol(Reloc.Index)->getGlobalIndex();
|
||||
case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
|
||||
if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) {
|
||||
size_t FunctionCodeOffset =
|
||||
getFunctionCodeOffset(Sym->Function->getFunctionBody());
|
||||
return Sym->Function->OutputOffset + FunctionCodeOffset + Reloc.Addend;
|
||||
}
|
||||
return 0;
|
||||
case R_WEBASSEMBLY_SECTION_OFFSET_I32:
|
||||
return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend;
|
||||
default:
|
||||
llvm_unreachable("unknown relocation type");
|
||||
}
|
||||
|
@ -147,14 +189,19 @@ void ObjFile::parse() {
|
|||
|
||||
// Find the code and data sections. Wasm objects can have at most one code
|
||||
// and one data section.
|
||||
uint32_t SectionIndex = 0;
|
||||
for (const SectionRef &Sec : WasmObj->sections()) {
|
||||
const WasmSection &Section = WasmObj->getWasmSection(Sec);
|
||||
if (Section.Type == WASM_SEC_CODE)
|
||||
if (Section.Type == WASM_SEC_CODE) {
|
||||
CodeSection = &Section;
|
||||
else if (Section.Type == WASM_SEC_DATA)
|
||||
} else if (Section.Type == WASM_SEC_DATA) {
|
||||
DataSection = &Section;
|
||||
else if (Section.Type == WASM_SEC_CUSTOM)
|
||||
} else if (Section.Type == WASM_SEC_CUSTOM) {
|
||||
CustomSections.emplace_back(make<InputSection>(Section, this));
|
||||
CustomSections.back()->copyRelocations(Section);
|
||||
CustomSectionsByIndex[SectionIndex] = CustomSections.back();
|
||||
}
|
||||
SectionIndex++;
|
||||
}
|
||||
|
||||
TypeMap.resize(getWasmObj()->types().size());
|
||||
|
@ -215,6 +262,10 @@ GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t Index) const {
|
|||
return cast<GlobalSymbol>(Symbols[Index]);
|
||||
}
|
||||
|
||||
SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const {
|
||||
return cast<SectionSymbol>(Symbols[Index]);
|
||||
}
|
||||
|
||||
DataSymbol *ObjFile::getDataSymbol(uint32_t Index) const {
|
||||
return cast<DataSymbol>(Symbols[Index]);
|
||||
}
|
||||
|
@ -253,14 +304,20 @@ Symbol *ObjFile::createDefined(const WasmSymbol &Sym) {
|
|||
return make<DefinedData>(Name, Flags, this, Seg, Offset, Size);
|
||||
return Symtab->addDefinedData(Name, Flags, this, Seg, Offset, Size);
|
||||
}
|
||||
case WASM_SYMBOL_TYPE_GLOBAL:
|
||||
case WASM_SYMBOL_TYPE_GLOBAL: {
|
||||
InputGlobal *Global =
|
||||
Globals[Sym.Info.ElementIndex - WasmObj->getNumImportedGlobals()];
|
||||
if (Sym.isBindingLocal())
|
||||
return make<DefinedGlobal>(Name, Flags, this, Global);
|
||||
return Symtab->addDefinedGlobal(Name, Flags, this, Global);
|
||||
}
|
||||
llvm_unreachable("unkown symbol kind");
|
||||
case WASM_SYMBOL_TYPE_SECTION: {
|
||||
InputSection *Section = CustomSectionsByIndex[Sym.Info.ElementIndex];
|
||||
assert(Sym.isBindingLocal());
|
||||
return make<SectionSymbol>(Name, Flags, Section, this);
|
||||
}
|
||||
}
|
||||
llvm_unreachable("unknown symbol kind");
|
||||
}
|
||||
|
||||
Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) {
|
||||
|
@ -274,8 +331,10 @@ Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) {
|
|||
return Symtab->addUndefinedData(Name, Flags, this);
|
||||
case WASM_SYMBOL_TYPE_GLOBAL:
|
||||
return Symtab->addUndefinedGlobal(Name, Flags, this, Sym.GlobalType);
|
||||
case WASM_SYMBOL_TYPE_SECTION:
|
||||
llvm_unreachable("section symbols cannot be undefined");
|
||||
}
|
||||
llvm_unreachable("unkown symbol kind");
|
||||
llvm_unreachable("unknown symbol kind");
|
||||
}
|
||||
|
||||
void ArchiveFile::parse() {
|
||||
|
|
|
@ -95,6 +95,7 @@ public:
|
|||
|
||||
uint32_t calcNewIndex(const WasmRelocation &Reloc) const;
|
||||
uint32_t calcNewValue(const WasmRelocation &Reloc) const;
|
||||
uint32_t calcNewAddend(const WasmRelocation &Reloc) const;
|
||||
uint32_t calcExpectedValue(const WasmRelocation &Reloc) const;
|
||||
|
||||
const WasmSection *CodeSection = nullptr;
|
||||
|
@ -110,12 +111,14 @@ public:
|
|||
std::vector<InputFunction *> Functions;
|
||||
std::vector<InputGlobal *> Globals;
|
||||
std::vector<InputSection *> CustomSections;
|
||||
llvm::DenseMap<uint32_t, InputSection *> CustomSectionsByIndex;
|
||||
|
||||
ArrayRef<Symbol *> getSymbols() const { return Symbols; }
|
||||
Symbol *getSymbol(uint32_t Index) const { return Symbols[Index]; }
|
||||
FunctionSymbol *getFunctionSymbol(uint32_t Index) const;
|
||||
DataSymbol *getDataSymbol(uint32_t Index) const;
|
||||
GlobalSymbol *getGlobalSymbol(uint32_t Index) const;
|
||||
SectionSymbol *getSectionSymbol(uint32_t Index) const;
|
||||
|
||||
private:
|
||||
Symbol *createDefined(const WasmSymbol &Sym);
|
||||
|
|
|
@ -224,3 +224,15 @@ void CustomSection::writeTo(uint8_t *Buf) {
|
|||
parallelForEach(InputSections,
|
||||
[&](const InputSection *Section) { Section->writeTo(Buf); });
|
||||
}
|
||||
|
||||
uint32_t CustomSection::numRelocations() const {
|
||||
uint32_t Count = 0;
|
||||
for (const InputSection *InputSect : InputSections)
|
||||
Count += InputSect->NumRelocations();
|
||||
return Count;
|
||||
}
|
||||
|
||||
void CustomSection::writeRelocations(raw_ostream &OS) const {
|
||||
for (const InputSection *S : InputSections)
|
||||
S->writeRelocations(OS);
|
||||
}
|
||||
|
|
|
@ -127,6 +127,8 @@ public:
|
|||
return Header.size() + NameData.size() + PayloadSize;
|
||||
}
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
uint32_t numRelocations() const override;
|
||||
void writeRelocations(raw_ostream &OS) const override;
|
||||
|
||||
protected:
|
||||
size_t PayloadSize;
|
||||
|
|
|
@ -36,6 +36,8 @@ WasmSymbolType Symbol::getWasmType() const {
|
|||
return llvm::wasm::WASM_SYMBOL_TYPE_DATA;
|
||||
if (isa<GlobalSymbol>(this))
|
||||
return llvm::wasm::WASM_SYMBOL_TYPE_GLOBAL;
|
||||
if (isa<SectionSymbol>(this))
|
||||
return llvm::wasm::WASM_SYMBOL_TYPE_SECTION;
|
||||
llvm_unreachable("invalid symbol kind");
|
||||
}
|
||||
|
||||
|
@ -194,6 +196,19 @@ DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
|
|||
Global ? &Global->getType() : nullptr),
|
||||
Global(Global) {}
|
||||
|
||||
uint32_t SectionSymbol::getOutputSectionIndex() const {
|
||||
DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n");
|
||||
assert(OutputSectionIndex != INVALID_INDEX);
|
||||
return OutputSectionIndex;
|
||||
}
|
||||
|
||||
void SectionSymbol::setOutputSectionIndex(uint32_t Index) {
|
||||
DEBUG(dbgs() << "setOutputSectionIndex: " << getName() << " -> " << Index
|
||||
<< "\n");
|
||||
assert(Index != INVALID_INDEX);
|
||||
OutputSectionIndex = Index;
|
||||
}
|
||||
|
||||
void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); }
|
||||
|
||||
std::string lld::toString(const wasm::Symbol &Sym) {
|
||||
|
@ -219,6 +234,8 @@ std::string lld::toString(wasm::Symbol::Kind Kind) {
|
|||
return "UndefinedGlobal";
|
||||
case wasm::Symbol::LazyKind:
|
||||
return "LazyKind";
|
||||
case wasm::Symbol::SectionKind:
|
||||
return "SectionKind";
|
||||
}
|
||||
llvm_unreachable("invalid symbol kind");
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ class InputChunk;
|
|||
class InputSegment;
|
||||
class InputFunction;
|
||||
class InputGlobal;
|
||||
class InputSection;
|
||||
|
||||
#define INVALID_INDEX UINT32_MAX
|
||||
|
||||
|
@ -40,6 +41,7 @@ public:
|
|||
DefinedFunctionKind,
|
||||
DefinedDataKind,
|
||||
DefinedGlobalKind,
|
||||
SectionKind,
|
||||
UndefinedFunctionKind,
|
||||
UndefinedDataKind,
|
||||
UndefinedGlobalKind,
|
||||
|
@ -50,7 +52,7 @@ public:
|
|||
|
||||
bool isDefined() const {
|
||||
return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind ||
|
||||
SymbolKind == DefinedGlobalKind;
|
||||
SymbolKind == DefinedGlobalKind || SymbolKind == SectionKind;
|
||||
}
|
||||
|
||||
bool isUndefined() const {
|
||||
|
@ -155,6 +157,23 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class SectionSymbol : public Symbol {
|
||||
public:
|
||||
static bool classof(const Symbol *S) { return S->kind() == SectionKind; }
|
||||
|
||||
SectionSymbol(StringRef Name, uint32_t Flags, const InputSection *S,
|
||||
InputFile *F = nullptr)
|
||||
: Symbol(Name, SectionKind, Flags, F), Section(S) {}
|
||||
|
||||
const InputSection *Section;
|
||||
|
||||
uint32_t getOutputSectionIndex() const;
|
||||
void setOutputSectionIndex(uint32_t Index);
|
||||
|
||||
protected:
|
||||
uint32_t OutputSectionIndex = INVALID_INDEX;
|
||||
};
|
||||
|
||||
class DataSymbol : public Symbol {
|
||||
public:
|
||||
static bool classof(const Symbol *S) {
|
||||
|
@ -301,6 +320,7 @@ union SymbolUnion {
|
|||
alignas(UndefinedFunction) char E[sizeof(UndefinedFunction)];
|
||||
alignas(UndefinedData) char F[sizeof(UndefinedData)];
|
||||
alignas(UndefinedGlobal) char G[sizeof(UndefinedGlobal)];
|
||||
alignas(SectionSymbol) char I[sizeof(SectionSymbol)];
|
||||
};
|
||||
|
||||
template <typename T, typename... ArgT>
|
||||
|
|
|
@ -67,6 +67,7 @@ private:
|
|||
void assignIndexes();
|
||||
void calculateImports();
|
||||
void calculateExports();
|
||||
void calculateCustomSections();
|
||||
void assignSymtab();
|
||||
void calculateTypes();
|
||||
void createOutputSegments();
|
||||
|
@ -114,6 +115,7 @@ private:
|
|||
std::vector<WasmInitEntry> InitFunctions;
|
||||
|
||||
llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
|
||||
llvm::StringMap<SectionSymbol *> CustomSectionSymbols;
|
||||
|
||||
// Elements that are used to construct the final output
|
||||
std::string Header;
|
||||
|
@ -299,18 +301,35 @@ void Writer::createExportSection() {
|
|||
}
|
||||
}
|
||||
|
||||
void Writer::calculateCustomSections() {
|
||||
log("calculateCustomSections");
|
||||
bool StripDebug = Config->StripDebug || Config->StripAll;
|
||||
for (ObjFile *File : Symtab->ObjectFiles) {
|
||||
for (InputSection *Section : File->CustomSections) {
|
||||
StringRef Name = Section->getName();
|
||||
// These custom sections are known the linker and synthesized rather than
|
||||
// blindly copied
|
||||
if (Name == "linking" || Name == "name" || Name.startswith("reloc."))
|
||||
continue;
|
||||
// .. or it is a debug section
|
||||
if (StripDebug && Name.startswith(".debug_"))
|
||||
continue;
|
||||
CustomSectionMapping[Name].push_back(Section);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Writer::createCustomSections() {
|
||||
log("createCustomSections");
|
||||
for (ObjFile *File : Symtab->ObjectFiles)
|
||||
for (InputSection *Section : File->CustomSections)
|
||||
CustomSectionMapping[Section->getName()].push_back(Section);
|
||||
|
||||
for (auto &Pair : CustomSectionMapping) {
|
||||
StringRef Name = Pair.first();
|
||||
// These custom sections are known the linker and synthesized rather than
|
||||
// blindly copied
|
||||
if (Name == "linking" || Name == "name" || Name.startswith("reloc."))
|
||||
continue;
|
||||
|
||||
auto P = CustomSectionSymbols.find(Name);
|
||||
if (P != CustomSectionSymbols.end()) {
|
||||
uint32_t SectionIndex = OutputSections.size();
|
||||
P->second->setOutputSectionIndex(SectionIndex);
|
||||
}
|
||||
|
||||
DEBUG(dbgs() << "createCustomSection: " << Name << "\n");
|
||||
OutputSections.push_back(make<CustomSection>(Name, Pair.second));
|
||||
}
|
||||
|
@ -375,8 +394,11 @@ void Writer::createRelocSections() {
|
|||
Name = "reloc.DATA";
|
||||
else if (OSec->Type == WASM_SEC_CODE)
|
||||
Name = "reloc.CODE";
|
||||
else if (OSec->Type == WASM_SEC_CUSTOM)
|
||||
Name = Saver.save("reloc." + OSec->Name);
|
||||
else
|
||||
llvm_unreachable("relocations only supported for code and data");
|
||||
llvm_unreachable(
|
||||
"relocations only supported for code, data, or custom sections");
|
||||
|
||||
SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, Name);
|
||||
raw_ostream &OS = Section->getStream();
|
||||
|
@ -452,8 +474,7 @@ void Writer::createLinkingSection() {
|
|||
writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
|
||||
if (Sym->isDefined())
|
||||
writeStr(Sub.OS, Sym->getName(), "sym name");
|
||||
} else {
|
||||
assert(isa<DataSymbol>(Sym));
|
||||
} else if (auto *D = dyn_cast<DataSymbol>(Sym)) {
|
||||
writeStr(Sub.OS, Sym->getName(), "sym name");
|
||||
if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
|
||||
writeUleb128(Sub.OS, DataSym->getOutputSegmentIndex(), "index");
|
||||
|
@ -461,6 +482,9 @@ void Writer::createLinkingSection() {
|
|||
"data offset");
|
||||
writeUleb128(Sub.OS, DataSym->getSize(), "data size");
|
||||
}
|
||||
} else {
|
||||
auto *S = cast<SectionSymbol>(Sym);
|
||||
writeUleb128(Sub.OS, S->getOutputSectionIndex(), "sym section index");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -751,12 +775,32 @@ void Writer::assignSymtab() {
|
|||
if (!Config->Relocatable)
|
||||
return;
|
||||
|
||||
StringMap<uint32_t> SectionSymbolIndices;
|
||||
|
||||
unsigned SymbolIndex = SymtabEntries.size();
|
||||
for (ObjFile *File : Symtab->ObjectFiles) {
|
||||
DEBUG(dbgs() << "Symtab entries: " << File->getName() << "\n");
|
||||
for (Symbol *Sym : File->getSymbols()) {
|
||||
if (Sym->getFile() != File)
|
||||
continue;
|
||||
|
||||
if (auto *S = dyn_cast<SectionSymbol>(Sym)) {
|
||||
StringRef Name = S->getName();
|
||||
if (CustomSectionMapping.count(Name) == 0)
|
||||
continue;
|
||||
|
||||
auto SSI = SectionSymbolIndices.find(Name);
|
||||
if (SSI != SectionSymbolIndices.end()) {
|
||||
Sym->setOutputSymbolIndex(SSI->second);
|
||||
continue;
|
||||
}
|
||||
|
||||
SectionSymbolIndices[Name] = SymbolIndex;
|
||||
CustomSectionSymbols[Name] = cast<SectionSymbol>(Sym);
|
||||
|
||||
Sym->markLive();
|
||||
}
|
||||
|
||||
// (Since this is relocatable output, GC is not performed so symbols must
|
||||
// be live.)
|
||||
assert(Sym->isLive());
|
||||
|
@ -855,6 +899,8 @@ void Writer::assignIndexes() {
|
|||
HandleRelocs(Chunk);
|
||||
for (InputChunk *Chunk : File->Segments)
|
||||
HandleRelocs(Chunk);
|
||||
for (auto &P : File->CustomSections)
|
||||
HandleRelocs(P);
|
||||
}
|
||||
|
||||
uint32_t GlobalIndex = NumImportedGlobals + InputGlobals.size();
|
||||
|
@ -976,6 +1022,8 @@ void Writer::run() {
|
|||
layoutMemory();
|
||||
log("-- calculateExports");
|
||||
calculateExports();
|
||||
log("-- calculateCustomSections");
|
||||
calculateCustomSections();
|
||||
log("-- assignSymtab");
|
||||
assignSymtab();
|
||||
|
||||
|
|
Loading…
Reference in New Issue