Index: test/wasm/call-indirect.ll =================================================================== --- test/wasm/call-indirect.ll +++ test/wasm/call-indirect.ll @@ -58,6 +58,26 @@ ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory Index: test/wasm/data-layout.ll =================================================================== --- test/wasm/data-layout.ll +++ test/wasm/data-layout.ll @@ -23,6 +23,26 @@ ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1024 ; CHECK-NEXT: - Type: I32 ; CHECK-NEXT: Mutable: false @@ -43,7 +63,7 @@ ; CHECK: - Type: DATA ; CHECK-NEXT: Relocations: ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 -; CHECK-NEXT: Index: 4 +; CHECK-NEXT: Index: 8 ; CHECK-NEXT: Offset: 0x0000001F ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 7 Index: test/wasm/init-array-cxx.ll =================================================================== --- /dev/null +++ test/wasm/init-array-cxx.ll @@ -0,0 +1,141 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: lld -flavor wasm -o %t.wasm %t.o --allow-undefined +; RUN: obj2yaml %t.wasm | FileCheck %s + +; ==== Generated from ==== +; extern void externalFn(void); // Avoid optimising out ctor calls +; +; struct StaticCtor { +; StaticCtor(); +; }; +; // Not inline to avoid a COMDAT: +; StaticCtor::StaticCtor() { externalFn(); } +; +; static StaticCtor staticCtor; +; +; void __attribute__((constructor)) ctorFunction() { externalFn(); } +; +; extern void (*const __init_array_start)(void), (*const __init_array_end)(void); +; +; typedef unsigned long uintptr_t; +; extern "C" void _start(void) { +; for (void (*const *i)(void) = &__init_array_start; +; (uintptr_t)i < (uintptr_t)&__init_array_end; +; ++i) { +; (*i)(); +; } +; } +; ======================== + + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +%struct.StaticCtor = type { i8 } + +@__init_array_start = external constant void ()*, align 4 +@__init_array_end = external constant void ()*, align 4 +@llvm.global_ctors = appending global [2 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_Z12ctorFunctionv, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_init_test.cxx, i8* null }] + +@_ZN10StaticCtorC1Ev = hidden alias %struct.StaticCtor* (%struct.StaticCtor*), %struct.StaticCtor* (%struct.StaticCtor*)* @_ZN10StaticCtorC2Ev + +; Function Attrs: optsize +define hidden %struct.StaticCtor* @_ZN10StaticCtorC2Ev(%struct.StaticCtor* readnone returned %this) unnamed_addr #0 { +entry: + tail call void @_Z10externalFnv() #2 + ret %struct.StaticCtor* %this +} + +; Function Attrs: optsize +declare void @_Z10externalFnv() local_unnamed_addr #1 + +; Function Attrs: optsize +define hidden void @_Z12ctorFunctionv() #0 { +entry: + tail call void @_Z10externalFnv() #2 + ret void +} + +; Function Attrs: optsize +define hidden void @_start() local_unnamed_addr #0 { +entry: + br i1 icmp ult (void ()** @__init_array_start, void ()** @__init_array_end), label %for.body.preheader, label %for.cond.cleanup + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup: ; preds = %for.body, %entry + ret void + +for.body: ; preds = %for.body.preheader, %for.body + %i.04 = phi void ()** [ %incdec.ptr, %for.body ], [ @__init_array_start, %for.body.preheader ] + %0 = load void ()*, void ()** %i.04, align 4, !tbaa !2 + tail call void %0() #2 + %incdec.ptr = getelementptr inbounds void ()*, void ()** %i.04, i32 1 + %cmp = icmp ult void ()** %incdec.ptr, @__init_array_end + br i1 %cmp, label %for.body, label %for.cond.cleanup +} + +; Function Attrs: optsize +define internal void @_GLOBAL__sub_I_init_test.cxx() #0 section ".text.__startup" { +entry: + tail call void @_Z10externalFnv() #2 + ret void +} + +attributes #0 = { optsize "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 = { optsize "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 #2 = { optsize } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 6.0.0 (trunk 318652)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"any pointer", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} + +; CHECK: - Type: IMPORT +; CHECK-NEXT: Imports: +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: _Z10externalFnv +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: SigIndex: 1 +; CHECK: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Type: START +; CHECK-NEXT: StartFunction: 3 +; CHECK-NEXT: - Type: ELEM +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1 +; CHECK-NEXT: Functions: [ 2, 4 ] +; CHECK-NEXT: - Type: CODE +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 10808080800020000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 1080808080000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Count: 1 +; CHECK-NEXT: Body: 418088808000210002404180888080004188888080004F0D000340200028020011818080800000200041046A2200418888808000490D000B0B0B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 1080808080000B +; CHECK-NEXT: - Type: DATA +; CHECK-NEXT: Segments: +; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Content: '0100000002000000' Index: test/wasm/init-array-empty.ll =================================================================== --- /dev/null +++ test/wasm/init-array-empty.ll @@ -0,0 +1,74 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: lld -flavor wasm -o %t.wasm %t.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +; ==== Generated from ==== +; extern void (*const __init_array_start)(void), (*const __init_array_end)(void); +; +; typedef unsigned long uintptr_t; +; extern "C" void _start(void) { +; for (void (*const *i)(void) = &__init_array_start; +; (uintptr_t)i < (uintptr_t)&__init_array_end; +; ++i) { +; (*i)(); +; } +; } +; ======================== + + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +@__init_array_start = external constant void ()*, align 4 +@__init_array_end = external constant void ()*, align 4 + +; Function Attrs: optsize +define hidden void @_start() local_unnamed_addr #0 { +entry: + br i1 icmp ult (void ()** @__init_array_start, void ()** @__init_array_end), label %for.body.preheader, label %for.cond.cleanup + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup: ; preds = %for.body, %entry + ret void + +for.body: ; preds = %for.body.preheader, %for.body + %i.04 = phi void ()** [ %incdec.ptr, %for.body ], [ @__init_array_start, %for.body.preheader ] + %0 = load void ()*, void ()** %i.04, align 4, !tbaa !2 + tail call void %0() #1 + %incdec.ptr = getelementptr inbounds void ()*, void ()** %i.04, i32 1 + %cmp = icmp ult void ()** %incdec.ptr, @__init_array_end + br i1 %cmp, label %for.body, label %for.cond.cleanup +} + +attributes #0 = { optsize "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 = { optsize } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 6.0.0 (trunk 318652)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"any pointer", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} + + +; CHECK: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Type: START +; CHECK-NEXT: StartFunction: 0 +; CHECK-NEXT: - Type: CODE +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Count: 1 +; CHECK-NEXT: Body: 418080808000210002404180808080004180808080004F0D000340200028020011808080800000200041046A2200418080808000490D000B0B0B Index: test/wasm/init-fini-array.ll =================================================================== --- /dev/null +++ test/wasm/init-fini-array.ll @@ -0,0 +1,95 @@ +; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s +; RUN: lld -flavor wasm %t.o -o %t.wasm +; RUN: obj2yaml %t.wasm | FileCheck %s + +define void @func1() { +entry: + ret void +} + +define void @func2() { +entry: + ret void +} + +define 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: - Type: GLOBAL +; CHECK-NEXT: Globals: +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1028 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1028 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1032 +; CHECK-NEXT: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: func1 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: func2 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Type: START +; CHECK-NEXT: StartFunction: 2 +; CHECK-NEXT: - Type: ELEM +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1 +; CHECK-NEXT: Functions: [ 0, 1 ] +; CHECK-NEXT: - Type: CODE +; 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: - Type: DATA +; CHECK-NEXT: Segments: +; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Content: '01000000' +; CHECK-NEXT: - SectionOffset: 17 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1028 +; CHECK-NEXT: Content: '02000000' Index: test/wasm/local-symbols.ll =================================================================== --- test/wasm/local-symbols.ll +++ test/wasm/local-symbols.ll @@ -46,6 +46,26 @@ ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory Index: test/wasm/stack-pointer.ll =================================================================== --- test/wasm/stack-pointer.ll +++ test/wasm/stack-pointer.ll @@ -40,6 +40,26 @@ ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory Index: test/wasm/weak-alias-overide.ll =================================================================== --- test/wasm/weak-alias-overide.ll +++ test/wasm/weak-alias-overide.ll @@ -48,6 +48,26 @@ ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory Index: test/wasm/weak-alias.ll =================================================================== --- test/wasm/weak-alias.ll +++ test/wasm/weak-alias.ll @@ -42,6 +42,26 @@ ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory Index: test/wasm/weak-external.ll =================================================================== --- test/wasm/weak-external.ll +++ test/wasm/weak-external.ll @@ -52,6 +52,26 @@ ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory Index: wasm/Config.h =================================================================== --- wasm/Config.h +++ wasm/Config.h @@ -41,6 +41,10 @@ std::vector SearchPaths; std::vector SyntheticGlobals; Symbol *StackPointerSymbol = nullptr; + Symbol *InitArrayStartSymbol = nullptr; + Symbol *InitArrayEndSymbol = nullptr; + Symbol *FiniArrayStartSymbol = nullptr; + Symbol *FiniArrayEndSymbol = nullptr; }; // The only instance of Configuration struct. Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -138,11 +138,9 @@ // Wasm global are used in relocatable object files to model symbol imports // and exports. In the final executable the only use of wasm globals is // for the exlicit stack pointer (__stack_pointer). -static Symbol* addSyntheticGlobal(StringRef Name, int32_t Value) { +static Symbol* addSyntheticGlobal(StringRef Name, uint32_t Value) { log("injecting global: " + Name); - Symbol *S = Symtab->addDefinedGlobal(Name); - S->setVirtualAddress(Value); - S->setOutputIndex(Config->SyntheticGlobals.size()); + Symbol *S = Symtab->addDefinedGlobal(Name, Value); Config->SyntheticGlobals.emplace_back(S); return S; } @@ -304,6 +302,10 @@ } Config->StackPointerSymbol = addSyntheticGlobal("__stack_pointer", 0); + Config->InitArrayStartSymbol = addSyntheticGlobal("__init_array_start", 0); + Config->InitArrayEndSymbol = addSyntheticGlobal("__init_array_end", 0); + Config->FiniArrayStartSymbol = addSyntheticGlobal("__fini_array_start", 0); + Config->FiniArrayEndSymbol = addSyntheticGlobal("__fini_array_end", 0); } createFiles(Args); Index: wasm/SymbolTable.h =================================================================== --- wasm/SymbolTable.h +++ wasm/SymbolTable.h @@ -53,7 +53,7 @@ const InputSegment *Segment = nullptr); Symbol *addUndefined(InputFile *F, const WasmSymbol *Sym); Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type); - Symbol *addDefinedGlobal(StringRef Name); + Symbol *addDefinedGlobal(StringRef Name, uint32_t Value); void addLazy(ArchiveFile *F, const Archive::Symbol *Sym); private: Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -135,15 +135,21 @@ "\n>>> defined as " + toString(*NewSig) + " in " + F.getName()); } -Symbol *SymbolTable::addDefinedGlobal(StringRef Name) { +Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Value) { DEBUG(dbgs() << "addDefinedGlobal: " << Name << "\n"); Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); - if (WasInserted) + if (WasInserted) { S->update(Symbol::DefinedGlobalKind); - else if (!S->isGlobal()) + S->setVirtualAddress(Value); + } else if (!S->isGlobal()) { error("symbol type mismatch: " + Name); + } else if (!S->isDefined()) { + DEBUG(dbgs() << "resolving existing undefined symbol: " << Name << "\n"); + S->update(Symbol::DefinedGlobalKind); + S->setVirtualAddress(Value); + } return S; } Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -84,6 +84,8 @@ // space of the output object. void setOutputIndex(uint32_t Index); + // Set the virtual address for a "synthetic" global variable - not used + // normally for symbols defined in the usual way. void setVirtualAddress(uint32_t VA); void update(Kind K, InputFile *F = nullptr, const WasmSymbol *Sym = nullptr, Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -221,6 +221,7 @@ raw_ostream &OS = Section->getStream(); writeUleb128(OS, NumGlobals, "global count"); + for (const Symbol *Sym : Config->SyntheticGlobals) { WasmGlobal Global; Global.Type = WASM_TYPE_I32; @@ -507,6 +508,17 @@ Seg->StartVA = MemoryPtr; debugPrint("mem: %-10s offset=%-8d size=%-4d align=%d\n", Seg->Name.str().c_str(), MemoryPtr, Seg->Size, Seg->Alignment); + + if (!Config->Relocatable) { + if (Seg->Name == ".init_array") { + Config->InitArrayStartSymbol->setVirtualAddress(MemoryPtr); + Config->InitArrayEndSymbol->setVirtualAddress(MemoryPtr + Seg->Size); + } else if (Seg->Name == ".fini_array") { + Config->FiniArrayStartSymbol->setVirtualAddress(MemoryPtr); + Config->FiniArrayEndSymbol->setVirtualAddress(MemoryPtr + Seg->Size); + } + } + MemoryPtr += Seg->Size; } @@ -569,9 +581,14 @@ } void Writer::calculateOffsets() { - NumGlobals = Config->SyntheticGlobals.size(); + NumGlobals = 0; NumTableElems = InitialTableOffset; + for (Symbol *Sym : Config->SyntheticGlobals) { + Sym->setOutputIndex(NumGlobals); + ++NumGlobals; + } + for (ObjFile *File : Symtab->ObjectFiles) { const WasmObjectFile *WasmFile = File->getWasmObj();