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: 1052 ; 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: 1 +; CHECK-NEXT: Index: 5 ; 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,139 @@ +; 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: 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,72 @@ +; 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: 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,93 @@ +; 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: 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 @@ -40,6 +40,10 @@ llvm::StringSet<> AllowUndefinedSymbols; std::vector SearchPaths; 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 @@ -142,6 +142,12 @@ Symtab->addUndefinedFunction(Name, Type); } +static Symbol *addDefinedGlobalWithDefault(StringRef Name, uint32_t DefaultAddr) { + Symbol *Sym = Symtab->addDefinedGlobal(Name); + Sym->setVirtualAddress(DefaultAddr); + return Sym; +} + static void printHelp(const char *Argv0) { WasmOptTable Table; Table.PrintHelp(outs(), Argv0, "LLVM Linker", false); @@ -284,6 +290,10 @@ addSyntheticUndefinedFunction(S, nullptr); Config->StackPointerSymbol = Symtab->addDefinedGlobal("__stack_pointer"); + Config->InitArrayStartSymbol = addDefinedGlobalWithDefault("__init_array_start", 0); + Config->InitArrayEndSymbol = addDefinedGlobalWithDefault("__init_array_end", 0); + Config->FiniArrayStartSymbol = addDefinedGlobalWithDefault("__fini_array_start", 0); + Config->FiniArrayEndSymbol = addDefinedGlobalWithDefault("__fini_array_end", 0); } createFiles(Args); Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -61,7 +61,6 @@ void Symbol::setVirtualAddress(uint32_t Value) { DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n"); - assert(!VirtualAddress.hasValue()); VirtualAddress = Value; } Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -273,6 +273,10 @@ // connot be exported. if (Sym == Config->StackPointerSymbol) continue; + // Don't export the .init_array/.fini_array symbols, they're only internal. + if (Sym == Config->InitArrayStartSymbol || Sym == Config->InitArrayEndSymbol || + Sym == Config->FiniArrayStartSymbol || Sym == Config->FiniArrayEndSymbol) + continue; SymbolExports.emplace_back(Sym); } @@ -464,6 +468,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; } @@ -603,9 +618,16 @@ void Writer::assignSymbolIndexes() { uint32_t GlobalIndex = GlobalImports.size(); - if (Config->StackPointerSymbol) { - DefinedGlobals.emplace_back(Config->StackPointerSymbol); - Config->StackPointerSymbol->setOutputIndex(GlobalIndex++); + Symbol *SyntheticGlobals[] = { + Config->StackPointerSymbol, + Config->InitArrayStartSymbol, Config->InitArrayEndSymbol, + Config->FiniArrayStartSymbol, Config->FiniArrayEndSymbol + }; + for (Symbol *Sym : SyntheticGlobals) { + if (Sym) { + DefinedGlobals.emplace_back(Sym); + Sym->setOutputIndex(GlobalIndex++); + } } if (Config->EmitRelocs)