Index: test/wasm/Inputs/global-ctor-dtor.ll =================================================================== --- test/wasm/Inputs/global-ctor-dtor.ll +++ test/wasm/Inputs/global-ctor-dtor.ll @@ -9,6 +9,14 @@ ret void } -@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @myctor, i8* null }] +@llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [ + { i32, void ()*, i8* } { i32 2002, void ()* @myctor, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @myctor, i8* null }, + { i32, void ()*, i8* } { i32 202, void ()* @myctor, i8* null } +] -@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @mydtor, i8* null }] +@llvm.global_dtors = appending global [3 x { i32, void ()*, i8* }] [ + { i32, void ()*, i8* } { i32 2002, void ()* @mydtor, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @mydtor, i8* null }, + { i32, void ()*, i8* } { i32 202, void ()* @mydtor, i8* null } +] Index: test/wasm/alias.ll =================================================================== --- test/wasm/alias.ll +++ test/wasm/alias.ll @@ -19,8 +19,11 @@ ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -55,6 +58,9 @@ ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 41000B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking ; CHECK-NEXT: DataSize: 0 @@ -63,4 +69,6 @@ ; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: start_alias +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: ... Index: test/wasm/call-indirect.ll =================================================================== --- test/wasm/call-indirect.ll +++ test/wasm/call-indirect.ll @@ -52,7 +52,7 @@ ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - I64 ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 2 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 2, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -114,6 +114,9 @@ ; CHECK-NEXT: - Index: 4 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 42012000118380808000001A0B +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 7 Index: test/wasm/function-imports-first.ll =================================================================== --- test/wasm/function-imports-first.ll +++ test/wasm/function-imports-first.ll @@ -22,7 +22,7 @@ ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - F32 ; CHECK: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1, 0 ] ; CHECK: - Type: CODE ; CHECK-NEXT: Functions: ; CHECK-NEXT: - Index: 0 @@ -31,6 +31,9 @@ ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 41000B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking ; CHECK-NEXT: DataSize: 0 @@ -41,4 +44,6 @@ ; CHECK-NEXT: Name: _start ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Name: ret32 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: ... Index: test/wasm/function-imports.ll =================================================================== --- test/wasm/function-imports.ll +++ test/wasm/function-imports.ll @@ -23,15 +23,18 @@ ; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1, 1 ] ; CHECK: - Type: CODE ; CHECK-NEXT: Functions: ; CHECK: - Index: 0 ; CHECK: - Index: 1 +; CHECK: - Index: 2 ; CHECK: Name: name ; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: ret32 ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: ... Index: test/wasm/init-fini.ll =================================================================== --- test/wasm/init-fini.ll +++ test/wasm/init-fini.ll @@ -11,6 +11,16 @@ ret void } +define hidden void @func3() { +entry: + ret void +} + +define hidden void @func4() { +entry: + ret void +} + define void @__cxa_atexit() { ret void } @@ -20,14 +30,31 @@ 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 }] +@llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [ + { i32, void ()*, i8* } { i32 1001, void ()* @func1, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @func1, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @func2, i8* null } +] + +@llvm.global_dtors = appending global [3 x { i32, void ()*, i8* }] [ + { i32, void ()*, i8* } { i32 1001, void ()* @func3, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @func3, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @func4, i8* null } +] ; RUN: lld -flavor wasm %t.o %t.global-ctor-dtor.o -o %t.wasm ; RUN: obj2yaml %t.wasm | FileCheck %s -; CHECK: Name: linking +; CHECK: - Type: ELEM +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1 +; CHECK-NEXT: Functions: [ 6, 9, 13, 15, 17 ] + +; CHECK: Body: 100010011007100B100E100B10101000100A100B10120B +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: linking ; CHECK-NEXT: DataSize: 0 ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name @@ -37,23 +64,41 @@ ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Name: func2 ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Name: __cxa_atexit +; CHECK-NEXT: Name: func3 ; CHECK-NEXT: - Index: 3 -; CHECK-NEXT: Name: _start +; CHECK-NEXT: Name: func4 ; CHECK-NEXT: - Index: 4 -; CHECK-NEXT: Name: .Lcall_dtors +; CHECK-NEXT: Name: __cxa_atexit ; CHECK-NEXT: - Index: 5 -; CHECK-NEXT: Name: .Lregister_call_dtors +; CHECK-NEXT: Name: _start ; CHECK-NEXT: - Index: 6 -; CHECK-NEXT: Name: .Lbitcast +; CHECK-NEXT: Name: .Lcall_dtors.101 ; CHECK-NEXT: - Index: 7 -; CHECK-NEXT: Name: myctor +; CHECK-NEXT: Name: .Lregister_call_dtors.101 ; CHECK-NEXT: - Index: 8 -; CHECK-NEXT: Name: mydtor +; CHECK-NEXT: Name: .Lbitcast ; CHECK-NEXT: - Index: 9 -; CHECK-NEXT: Name: .Lcall_dtors +; CHECK-NEXT: Name: .Lcall_dtors.1001 ; CHECK-NEXT: - Index: 10 -; CHECK-NEXT: Name: .Lregister_call_dtors +; CHECK-NEXT: Name: .Lregister_call_dtors.1001 +; CHECK-NEXT: - Index: 11 +; CHECK-NEXT: Name: myctor +; CHECK-NEXT: - Index: 12 +; CHECK-NEXT: Name: mydtor +; CHECK-NEXT: - Index: 13 +; CHECK-NEXT: Name: .Lcall_dtors.101 +; CHECK-NEXT: - Index: 14 +; CHECK-NEXT: Name: .Lregister_call_dtors.101 +; CHECK-NEXT: - Index: 15 +; CHECK-NEXT: Name: .Lcall_dtors.202 +; CHECK-NEXT: - Index: 16 +; CHECK-NEXT: Name: .Lregister_call_dtors.202 +; CHECK-NEXT: - Index: 17 +; CHECK-NEXT: Name: .Lcall_dtors.2002 +; CHECK-NEXT: - Index: 18 +; CHECK-NEXT: Name: .Lregister_call_dtors.2002 +; CHECK-NEXT: - Index: 19 +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: ... @@ -63,14 +108,28 @@ ; RELOC: Name: linking ; RELOC-NEXT: DataSize: 0 ; RELOC-NEXT: InitFunctions: -; RELOC-NEXT: - Priority: 65535 +; RELOC-NEXT: - Priority: 101 ; RELOC-NEXT: FunctionIndex: 0 -; RELOC-NEXT: - Priority: 65535 -; RELOC-NEXT: FunctionIndex: 5 -; RELOC-NEXT: - Priority: 65535 +; RELOC-NEXT: - Priority: 101 +; RELOC-NEXT: FunctionIndex: 1 +; RELOC-NEXT: - Priority: 101 ; RELOC-NEXT: FunctionIndex: 7 -; RELOC-NEXT: - Priority: 65535 +; RELOC-NEXT: - Priority: 101 +; RELOC-NEXT: FunctionIndex: 11 +; RELOC-NEXT: - Priority: 101 +; RELOC-NEXT: FunctionIndex: 14 +; RELOC-NEXT: - Priority: 202 +; RELOC-NEXT: FunctionIndex: 11 +; RELOC-NEXT: - Priority: 202 +; RELOC-NEXT: FunctionIndex: 16 +; RELOC-NEXT: - Priority: 1001 +; RELOC-NEXT: FunctionIndex: 0 +; RELOC-NEXT: - Priority: 1001 ; RELOC-NEXT: FunctionIndex: 10 +; RELOC-NEXT: - Priority: 2002 +; RELOC-NEXT: FunctionIndex: 11 +; RELOC-NEXT: - Priority: 2002 +; RELOC-NEXT: FunctionIndex: 18 ; RELOC-NEXT: - Type: CUSTOM ; RELOC-NEXT: Name: name ; RELOC-NEXT: FunctionNames: @@ -79,21 +138,37 @@ ; RELOC-NEXT: - Index: 1 ; RELOC-NEXT: Name: func2 ; RELOC-NEXT: - Index: 2 -; RELOC-NEXT: Name: __cxa_atexit +; RELOC-NEXT: Name: func3 ; RELOC-NEXT: - Index: 3 -; RELOC-NEXT: Name: _start +; RELOC-NEXT: Name: func4 ; RELOC-NEXT: - Index: 4 -; RELOC-NEXT: Name: .Lcall_dtors +; RELOC-NEXT: Name: __cxa_atexit ; RELOC-NEXT: - Index: 5 -; RELOC-NEXT: Name: .Lregister_call_dtors +; RELOC-NEXT: Name: _start ; RELOC-NEXT: - Index: 6 -; RELOC-NEXT: Name: .Lbitcast +; RELOC-NEXT: Name: .Lcall_dtors.101 ; RELOC-NEXT: - Index: 7 -; RELOC-NEXT: Name: myctor +; RELOC-NEXT: Name: .Lregister_call_dtors.101 ; RELOC-NEXT: - Index: 8 -; RELOC-NEXT: Name: mydtor +; RELOC-NEXT: Name: .Lbitcast ; RELOC-NEXT: - Index: 9 -; RELOC-NEXT: Name: .Lcall_dtors +; RELOC-NEXT: Name: .Lcall_dtors.1001 ; RELOC-NEXT: - Index: 10 -; RELOC-NEXT: Name: .Lregister_call_dtors +; RELOC-NEXT: Name: .Lregister_call_dtors.1001 +; RELOC-NEXT: - Index: 11 +; RELOC-NEXT: Name: myctor +; RELOC-NEXT: - Index: 12 +; RELOC-NEXT: Name: mydtor +; RELOC-NEXT: - Index: 13 +; RELOC-NEXT: Name: .Lcall_dtors.101 +; RELOC-NEXT: - Index: 14 +; RELOC-NEXT: Name: .Lregister_call_dtors.101 +; RELOC-NEXT: - Index: 15 +; RELOC-NEXT: Name: .Lcall_dtors.202 +; RELOC-NEXT: - Index: 16 +; RELOC-NEXT: Name: .Lregister_call_dtors.202 +; RELOC-NEXT: - Index: 17 +; RELOC-NEXT: Name: .Lcall_dtors.2002 +; RELOC-NEXT: - Index: 18 +; RELOC-NEXT: Name: .Lregister_call_dtors.2002 ; RELOC-NEXT: ... Index: test/wasm/local-symbols.ll =================================================================== --- test/wasm/local-symbols.ll +++ test/wasm/local-symbols.ll @@ -24,8 +24,11 @@ ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 0, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -60,6 +63,9 @@ ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 41010B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 7 @@ -78,4 +84,6 @@ ; CHECK-NEXT: Name: baz ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: ... Index: test/wasm/stack-pointer.ll =================================================================== --- test/wasm/stack-pointer.ll +++ test/wasm/stack-pointer.ll @@ -18,8 +18,11 @@ ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -46,6 +49,9 @@ ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __wasm_call_ctors +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Relocations: ; CHECK-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB @@ -55,6 +61,9 @@ ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 23808080800041106B1A41000B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking ; CHECK-NEXT: DataSize: 0 @@ -63,4 +72,6 @@ ; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: ... Index: test/wasm/weak-alias-overide.ll =================================================================== --- test/wasm/weak-alias-overide.ll +++ test/wasm/weak-alias-overide.ll @@ -30,7 +30,7 @@ ; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 0, 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 0, 0, 0, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -108,6 +108,9 @@ ; CHECK-NEXT: - Type: I32 ; CHECK-NEXT: Count: 2 ; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081082808080002101200041106A24808080800020010B +; CHECK-NEXT: - Index: 7 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking ; CHECK-NEXT: DataSize: 0 @@ -128,4 +131,6 @@ ; CHECK-NEXT: Name: call_alias_ptr ; CHECK-NEXT: - Index: 6 ; CHECK-NEXT: Name: call_direct_ptr +; CHECK-NEXT: - Index: 7 +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: ... Index: test/wasm/weak-alias.ll =================================================================== --- test/wasm/weak-alias.ll +++ test/wasm/weak-alias.ll @@ -23,8 +23,11 @@ ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 0, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -99,6 +102,9 @@ ; CHECK-NEXT: - Type: I32 ; CHECK-NEXT: Count: 2 ; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081081808080002101200041106A24808080800020010B +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking ; CHECK-NEXT: DataSize: 0 @@ -117,4 +123,6 @@ ; CHECK-NEXT: Name: call_alias_ptr ; CHECK-NEXT: - Index: 5 ; CHECK-NEXT: Name: call_direct_ptr +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: ... Index: test/wasm/weak-symbols.ll =================================================================== --- test/wasm/weak-symbols.ll +++ test/wasm/weak-symbols.ll @@ -23,8 +23,11 @@ ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -83,6 +86,9 @@ ; CHECK-NEXT: - Index: 4 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4181808080000B +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 7 @@ -103,4 +109,6 @@ ; CHECK-NEXT: Name: exportWeak1 ; CHECK-NEXT: - Index: 4 ; CHECK-NEXT: Name: exportWeak2 +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: ... Index: test/wasm/weak-undefined.ll =================================================================== --- test/wasm/weak-undefined.ll +++ test/wasm/weak-undefined.ll @@ -33,8 +33,11 @@ ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -78,6 +81,9 @@ ; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280280808080000B +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking ; CHECK-NEXT: DataSize: 0 Index: wasm/Config.h =================================================================== --- wasm/Config.h +++ wasm/Config.h @@ -40,6 +40,7 @@ llvm::StringSet<> AllowUndefinedSymbols; std::vector SearchPaths; Symbol *StackPointerSymbol = nullptr; + Symbol *CtorSymbol = nullptr; }; // The only instance of Configuration struct. Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -291,15 +291,16 @@ error("undefined symbols specified for relocatable output file"); if (!Config->Relocatable) { - if (!Config->Entry.empty()) { - static WasmSignature Signature = {{}, WASM_TYPE_NORESULT}; + static WasmSignature Signature = {{}, WASM_TYPE_NORESULT}; + if (!Config->Entry.empty()) addSyntheticUndefinedFunction(Config->Entry, &Signature); - } // Handle the `--undefined ` options. for (StringRef S : args::getStrings(Args, OPT_undefined)) addSyntheticUndefinedFunction(S, nullptr); + Config->CtorSymbol = Symtab->addDefinedFunction( + "__wasm_call_ctors", &Signature, WASM_SYMBOL_VISIBILITY_HIDDEN); Config->StackPointerSymbol = Symtab->addDefinedGlobal("__stack_pointer"); } Index: wasm/InputChunks.h =================================================================== --- wasm/InputChunks.h +++ wasm/InputChunks.h @@ -50,7 +50,7 @@ std::vector OutRelocations; protected: - InputChunk(const ObjFile &F) : File(F) {} + InputChunk(const ObjFile *F) : File(F) {} virtual ~InputChunk() = default; void calcRelocations(); virtual const uint8_t *getData() const = 0; @@ -58,7 +58,7 @@ std::vector Relocations; int32_t OutputOffset = 0; - const ObjFile &File; + const ObjFile *File; }; // Represents a WebAssembly data segment which can be included as part of @@ -71,7 +71,7 @@ // each global variable. class InputSegment : public InputChunk { public: - InputSegment(const WasmSegment &Seg, const ObjFile &F) + InputSegment(const WasmSegment &Seg, const ObjFile *F) : InputChunk(F), Segment(Seg) {} // Translate an offset in the input segment to an offset in the output @@ -108,21 +108,18 @@ // combined to create the final output CODE section. class InputFunction : public InputChunk { public: - InputFunction(const WasmSignature &S, const WasmFunction &Func, - const ObjFile &F) + InputFunction(const WasmSignature &S, const WasmFunction *Func, + const ObjFile *F) : InputChunk(F), Signature(S), WrittenToNameSec(false), Function(Func) {} - uint32_t getSize() const override { return Function.Size; } + uint32_t getSize() const override { return Function->Size; } const uint8_t *getData() const override { - return File.CodeSection->Content.data() + getInputSectionOffset(); + return File->CodeSection->Content.data() + getInputSectionOffset(); } uint32_t getOutputIndex() const { return OutputIndex.getValue(); }; bool hasOutputIndex() const { return OutputIndex.hasValue(); }; - void setOutputIndex(uint32_t Index) { - assert(!hasOutputIndex()); - OutputIndex = Index; - }; + void setOutputIndex(uint32_t Index); const WasmSignature &Signature; @@ -130,12 +127,26 @@ protected: uint32_t getInputSectionOffset() const override { - return Function.CodeSectionOffset; + return Function->CodeSectionOffset; } - const WasmFunction &Function; + const WasmFunction *Function; llvm::Optional OutputIndex; }; +class SyntheticFunction : public InputFunction { +public: + SyntheticFunction(const WasmSignature &S, StringRef Body) + : InputFunction(S, nullptr, nullptr), Body(Body) {} + + uint32_t getSize() const override { return Body.size(); } + const uint8_t *getData() const override { + return reinterpret_cast(Body.data()); + } + +protected: + StringRef Body; +}; + } // namespace wasm } // namespace lld Index: wasm/InputChunks.cpp =================================================================== --- wasm/InputChunks.cpp +++ wasm/InputChunks.cpp @@ -30,6 +30,8 @@ } void InputChunk::copyRelocations(const WasmSection &Section) { + if (Section.Relocations.empty()) + return; size_t Start = getInputSectionOffset(); size_t Size = getSize(); for (const WasmRelocation &R : Section.Relocations) @@ -92,8 +94,10 @@ // output section. Calculates the updated index and offset for each relocation // as well as the value to write out in the final binary. void InputChunk::calcRelocations() { + if (Relocations.empty()) + return; int32_t Off = getOutputOffset() - getInputSectionOffset(); - DEBUG(dbgs() << "calcRelocations: " << File.getName() + DEBUG(dbgs() << "calcRelocations: " << File->getName() << " offset=" << Twine(Off) << "\n"); for (const WasmRelocation &Reloc : Relocations) { OutputRelocation NewReloc; @@ -105,19 +109,25 @@ << " newOffset=" << NewReloc.Reloc.Offset << "\n"); if (Config->EmitRelocs) - NewReloc.NewIndex = File.calcNewIndex(Reloc); + NewReloc.NewIndex = File->calcNewIndex(Reloc); switch (Reloc.Type) { case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case R_WEBASSEMBLY_MEMORY_ADDR_I32: case R_WEBASSEMBLY_MEMORY_ADDR_LEB: - NewReloc.Value = File.getRelocatedAddress(Reloc.Index) + Reloc.Addend; + NewReloc.Value = File->getRelocatedAddress(Reloc.Index) + Reloc.Addend; break; default: - NewReloc.Value = File.calcNewIndex(Reloc); + NewReloc.Value = File->calcNewIndex(Reloc); break; } OutRelocations.emplace_back(NewReloc); } } + +void InputFunction::setOutputIndex(uint32_t Index) { + DEBUG(dbgs() << "InputFunction::setOutputIndex: " << Index << "\n"); + assert(!hasOutputIndex()); + OutputIndex = Index; +}; Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -188,7 +188,7 @@ GlobalSymbols.resize(NumGlobalImports + WasmObj->globals().size()); for (const WasmSegment &S : WasmObj->dataSegments()) { - InputSegment *Seg = make(S, *this); + InputSegment *Seg = make(S, this); Seg->copyRelocations(*DataSection); Segments.emplace_back(Seg); } @@ -199,7 +199,7 @@ for (size_t I = 0; I < Funcs.size(); ++I) { const WasmFunction &Func = Funcs[I]; const WasmSignature &Sig = Types[FuncTypes[I]]; - InputFunction *F = make(Sig, Func, *this); + InputFunction *F = make(Sig, &Func, this); F->copyRelocations(*CodeSection); Functions.emplace_back(F); } @@ -232,14 +232,10 @@ Symbols.push_back(S); if (WasmSym.isFunction()) { - DEBUG(dbgs() << "Function: " << WasmSym.ElementIndex << " -> " - << toString(*S) << "\n"); FunctionSymbols[WasmSym.ElementIndex] = S; if (WasmSym.HasAltIndex) FunctionSymbols[WasmSym.AltIndex] = S; } else { - DEBUG(dbgs() << "Global: " << WasmSym.ElementIndex << " -> " - << toString(*S) << "\n"); GlobalSymbols[WasmSym.ElementIndex] = S; if (WasmSym.HasAltIndex) GlobalSymbols[WasmSym.AltIndex] = S; Index: wasm/SymbolTable.h =================================================================== --- wasm/SymbolTable.h +++ wasm/SymbolTable.h @@ -55,6 +55,8 @@ InputFile *F, const WasmSignature *Signature = nullptr); Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type); Symbol *addDefinedGlobal(StringRef Name); + Symbol *addDefinedFunction(StringRef Name, const WasmSignature *Type, + uint32_t Flags); void addLazy(ArchiveFile *F, const Archive::Symbol *Sym); private: Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -119,6 +119,22 @@ " in " + F.getName()); } +Symbol *SymbolTable::addDefinedFunction(StringRef Name, + const WasmSignature *Type, + uint32_t Flags) { + DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n"); + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + if (WasInserted) { + S->update(Symbol::DefinedFunctionKind, nullptr, Flags); + S->setFunctionType(Type); + } else if (!S->isFunction()) { + error("symbol type mismatch: " + Name); + } + return S; +} + Symbol *SymbolTable::addDefinedGlobal(StringRef Name) { DEBUG(dbgs() << "addDefinedGlobal: " << Name << "\n"); Symbol *S; Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -9,6 +9,7 @@ #include "Writer.h" +#include "llvm/ADT/DenseSet.h" #include "Config.h" #include "InputChunks.h" #include "OutputSections.h" @@ -70,6 +71,8 @@ uint32_t lookupType(const WasmSignature &Sig); uint32_t registerType(const WasmSignature &Sig); + void createCtorFunction(); + void calculateInitFunctions(); void assignIndexes(); void calculateImports(); void calculateOffsets(); @@ -114,12 +117,15 @@ std::vector DefinedGlobals; std::vector DefinedFunctions; std::vector IndirectFunctions; + std::vector InitFunctions; // Elements that are used to construct the final output std::string Header; std::vector OutputSections; std::unique_ptr Buffer; + std::unique_ptr CtorFunction; + std::string CtorFunctionBody; std::vector Segments; llvm::SmallDenseMap SegmentMap; @@ -410,15 +416,6 @@ 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(), @@ -437,25 +434,40 @@ // Create an array of all function sorted by function index space std::vector Names; + auto AddToNames = [&](Symbol* S) { + if (!S->isFunction() || S->WrittenToNameSec) + return; + // We also need to guard against two different symbols (two different + // names) for the same wasm function. While this is possible (aliases) + // it is not legal in the "name" section. + InputFunction *Function = S->getFunction(); + if (Function) { + if (Function->WrittenToNameSec) + return; + Function->WrittenToNameSec = true; + } + S->WrittenToNameSec = true; + Names.emplace_back(S); + }; + for (ObjFile *File : Symtab->ObjectFiles) { Names.reserve(Names.size() + File->getSymbols().size()); + DEBUG(dbgs() << "adding names from: " << File->getName() << "\n"); for (Symbol *S : File->getSymbols()) { - if (!S->isFunction() || S->isWeak() || S->WrittenToNameSec) + if (S->isWeak()) continue; - // We also need to guard against two different symbols (two different - // names) for the same wasm function. While this is possible (aliases) - // it is not legal in the "name" section. - InputFunction *Function = S->getFunction(); - if (Function) { - if (Function->WrittenToNameSec) - continue; - Function->WrittenToNameSec = true; - } - S->WrittenToNameSec = true; - Names.emplace_back(S); + AddToNames(S); } } + DEBUG(dbgs() << "adding symtab names\n"); + for (Symbol *S : Symtab->getSymbols()) { + DEBUG(dbgs() << "sym: " << S->getName() << "\n"); + if (S->getFile()) + continue; + AddToNames(S); + } + SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "name"); std::sort(Names.begin(), Names.end(), [](const Symbol *A, const Symbol *B) { @@ -603,11 +615,15 @@ for (const WasmSignature &Sig : File->getWasmObj()->types()) File->TypeMap.push_back(registerType(Sig)); } + + for (Symbol *Sym : Symtab->getSymbols()) + if (Sym->isFunction()) + registerType(Sym->getFunctionType()); } void Writer::assignIndexes() { - uint32_t GlobalIndex = ImportedGlobals.size(); - uint32_t FunctionIndex = ImportedFunctions.size(); + uint32_t GlobalIndex = ImportedGlobals.size() + DefinedGlobals.size(); + uint32_t FunctionIndex = ImportedFunctions.size() + DefinedFunctions.size(); if (Config->StackPointerSymbol) { DefinedGlobals.emplace_back(Config->StackPointerSymbol); @@ -686,6 +702,57 @@ } } +static const int OPCODE_CALL = 0x10; +static const int OPCODE_END = 0xb; + +// Create synthetic "__wasm_call_ctors" function based on ctor functions +// in input object. +void Writer::createCtorFunction() { + uint32_t FunctionIndex = ImportedFunctions.size() + DefinedFunctions.size(); + Config->CtorSymbol->setOutputIndex(FunctionIndex); + + // First write the body bytes to a string. + std::string FunctionBody; + static WasmSignature Signature = {{}, WASM_TYPE_NORESULT}; + { + raw_string_ostream OS(FunctionBody); + writeUleb128(OS, 0, "num locals"); + for (const WasmInitFunc &F : InitFunctions) { + writeU8(OS, OPCODE_CALL, "CALL"); + writeUleb128(OS, F.FunctionIndex, "function index"); + } + writeU8(OS, OPCODE_END, "END"); + } + + // Once we know the size of the body we can create the final function body + raw_string_ostream OS(CtorFunctionBody); + writeUleb128(OS, FunctionBody.size(), "function size"); + OS.flush(); + CtorFunctionBody += FunctionBody; + CtorFunction = + llvm::make_unique(Signature, CtorFunctionBody); + DefinedFunctions.emplace_back(CtorFunction.get()); +} + +// Populate InitFunctions vector with init functions from all input objects. +// This is then used either when creating the output linking section or to +// synthesize the "__wasm_call_ctors" function. +void Writer::calculateInitFunctions() { + 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)}); + } + // Sort in order of priority (lowest first) so that they are called + // in the correct order. + std::sort(InitFunctions.begin(), InitFunctions.end(), + [](const WasmInitFunc &L, const WasmInitFunc &R) { + return L.Priority < R.Priority; + }); +} + void Writer::run() { if (!Config->Relocatable) InitialTableOffset = 1; @@ -696,6 +763,10 @@ calculateImports(); log("-- assignIndexes"); assignIndexes(); + log("-- calculateInitFunctions"); + calculateInitFunctions(); + if (!Config->Relocatable) + createCtorFunction(); if (errorHandler().Verbose) { log("Defined Functions: " + Twine(DefinedFunctions.size()));