Index: test/wasm/Inputs/global-ctor-dtor.ll =================================================================== --- /dev/null +++ test/wasm/Inputs/global-ctor-dtor.ll @@ -0,0 +1,14 @@ +define hidden void @myctor() { +entry: + ret void +} + +define hidden void @mydtor() { +entry: + %ptr = alloca i32 + ret void +} + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @myctor, i8* null }] + +@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @mydtor, i8* null }] Index: test/wasm/init-fini.ll =================================================================== --- /dev/null +++ test/wasm/init-fini.ll @@ -0,0 +1,174 @@ +; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s +; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/global-ctor-dtor.ll -o %t.global-ctor-dtor.o +; RUN: lld -flavor wasm -r %t.o %t.global-ctor-dtor.o -o %t.wasm +; RUN: obj2yaml %t.wasm | FileCheck %s + +define hidden void @func1() { +entry: + ret void +} + +define hidden void @func2() { +entry: + + ret void +} + +define hidden void @_start() { +entry: + ret void +} + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func1, i8* null }] + +@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func2, i8* null }] + +; CHECK: --- !WASM +; CHECK-NEXT: FileHeader: +; CHECK-NEXT: Version: 0x00000001 +; CHECK-NEXT: Sections: +; CHECK-NEXT: - Type: TYPE +; CHECK-NEXT: Signatures: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - I32 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - I32 +; CHECK-NEXT: - I32 +; CHECK-NEXT: - I32 +; CHECK-NEXT: - Type: IMPORT +; CHECK-NEXT: Imports: +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: __cxa_atexit +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: SigIndex: 2 +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: __stack_pointer +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: GlobalType: I32 +; CHECK-NEXT: GlobalMutable: false +; CHECK-NEXT: - Type: FUNCTION +; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 1, 0, 0, 0, 1, 0 ] +; CHECK-NEXT: - Type: TABLE +; CHECK-NEXT: Tables: +; CHECK-NEXT: - ElemType: ANYFUNC +; CHECK-NEXT: Limits: +; CHECK-NEXT: Flags: [ HAS_MAX ] +; CHECK-NEXT: Initial: 0x00000002 +; CHECK-NEXT: Maximum: 0x00000002 +; CHECK-NEXT: - Type: MEMORY +; CHECK-NEXT: Memories: +; CHECK-NEXT: - Initial: 0x00000000 +; CHECK-NEXT: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: func1 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: func2 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: myctor +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 6 +; CHECK-NEXT: - Name: mydtor +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 7 +; CHECK-NEXT: - Type: ELEM +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: Functions: [ 4, 8 ] +; CHECK-NEXT: - Type: CODE +; CHECK-NEXT: Relocations: +; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: Offset: 0x0000000D +; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Offset: 0x00000018 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Offset: 0x00000020 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Offset: 0x00000026 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Offset: 0x00000038 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; CHECK-NEXT: Index: 7 +; CHECK-NEXT: Offset: 0x00000045 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Offset: 0x00000050 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Offset: 0x00000058 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Offset: 0x0000005E +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 1082808080000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 0240418080808000410041FFFFFFFF7F1080808080000D000F0B00000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 23808080800041106B1A0B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 1087808080000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 0240418180808000410041FFFFFFFF7F1080808080000D000F0B00000B +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: linking +; CHECK-NEXT: DataSize: 0 +; CHECK-NEXT: InitFunctions: +; CHECK-NEXT: - Priority: 65535 +; CHECK-NEXT: FunctionIndex: 1 +; CHECK-NEXT: - Priority: 65535 +; CHECK-NEXT: FunctionIndex: 5 +; CHECK-NEXT: - Priority: 65535 +; CHECK-NEXT: FunctionIndex: 6 +; CHECK-NEXT: - Priority: 65535 +; CHECK-NEXT: FunctionIndex: 9 +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __cxa_atexit +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: func1 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: func2 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Name: .Lcall_dtors +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Name: .Lregister_call_dtors +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Name: myctor +; CHECK-NEXT: - Index: 7 +; CHECK-NEXT: Name: mydtor +; CHECK-NEXT: - Index: 8 +; CHECK-NEXT: Name: .Lcall_dtors +; CHECK-NEXT: - Index: 9 +; CHECK-NEXT: Name: .Lregister_call_dtors +; CHECK-NEXT: ... Index: wasm/OutputSections.h =================================================================== --- wasm/OutputSections.h +++ wasm/OutputSections.h @@ -37,6 +37,8 @@ virtual ~OutputSection() = default; + std::string getSectionName(); + void setOffset(size_t NewOffset) { log("setOffset: " + toString(this) + " -> " + Twine(NewOffset)); Offset = NewOffset; @@ -97,6 +99,8 @@ public: explicit SubSection(uint32_t Type) : SyntheticSection(Type) {} + std::string getSectionName(); + void writeToStream(raw_ostream &OS) { writeBytes(OS, Header.data(), Header.size()); writeBytes(OS, Body.data(), Body.size()); Index: wasm/OutputSections.cpp =================================================================== --- wasm/OutputSections.cpp +++ wasm/OutputSections.cpp @@ -176,10 +176,18 @@ } } +std::string OutputSection::getSectionName() { + return sectionTypeToString(Type); +} + +std::string SubSection::getSectionName() { + return std::string("subsection "; +} + void OutputSection::createHeader(size_t BodySize) { raw_string_ostream OS(Header); debugWrite(OS.tell(), - "section type [" + Twine(sectionTypeToString(Type)) + "]"); + "section type [" + Twine(getSectionName()) + "]"); writeUleb128(OS, Type, nullptr); writeUleb128(OS, BodySize, "section size"); OS.flush(); Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -398,7 +398,10 @@ DataSizeSubSection.finalizeContents(); DataSizeSubSection.writeToStream(OS); - if (Segments.size() && Config->Relocatable) { + if (!Config->Relocatable) + return; + + if (Segments.size()) { SubSection SubSection(WASM_SEGMENT_INFO); writeUleb128(SubSection.getStream(), Segments.size(), "num data segments"); for (const OutputSegment *S : Segments) { @@ -409,6 +412,27 @@ SubSection.finalizeContents(); SubSection.writeToStream(OS); } + + std::vector InitFunctions; + for (ObjFile *File : Symtab->ObjectFiles) { + const WasmLinkingData &L = File->getWasmObj()->linkingData(); + InitFunctions.reserve(InitFunctions.size() + L.InitFunctions.size()); + for (const WasmInitFunc &F: L.InitFunctions) { + InitFunctions.emplace_back(WasmInitFunc{ + F.Priority, File->relocateFunctionIndex(F.FunctionIndex)}); + } + } + + if (!InitFunctions.empty()) { + SubSection SubSection(WASM_INIT_FUNCS); + writeUleb128(SubSection.getStream(), InitFunctions.size(), "num init functionsw"); + for (const WasmInitFunc &F: InitFunctions) { + writeUleb128(SubSection.getStream(), F.Priority, "priority"); + writeUleb128(SubSection.getStream(), F.FunctionIndex, "function index"); + } + SubSection.finalizeContents(); + SubSection.writeToStream(OS); + } } // Create the custom "name" section containing debug symbol names.