Index: test/wasm/init-fini-array.ll =================================================================== --- /dev/null +++ test/wasm/init-fini-array.ll @@ -0,0 +1,105 @@ +; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s +; RUN: lld -flavor wasm -r %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: 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: 4 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 4 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 8 +; CHECK-NEXT: - Type: EXPORT +; CHECK-NEXT: Exports: +; 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: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: __init_array_start +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __init_array_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __fini_array_start +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: __fini_array_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Type: ELEM +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; 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: Relocations: +; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Offset: 0x00000006 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Offset: 0x0000000F +; CHECK-NEXT: Segments: +; CHECK-NEXT: - SectionOffset: 6 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: Content: '00000000' +; CHECK-NEXT: - SectionOffset: 15 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 4 +; CHECK-NEXT: Content: '01000000' + Index: wasm/Config.h =================================================================== --- wasm/Config.h +++ wasm/Config.h @@ -40,7 +40,6 @@ llvm::StringSet<> AllowUndefinedSymbols; std::vector SearchPaths; - std::vector> SyntheticGlobals; }; // The only instance of Configuration struct. Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -134,23 +134,6 @@ return None; } -// Inject a new wasm global into the output binary with the given value. -// 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 void addSyntheticGlobal(StringRef Name, int32_t Value) { - log("injecting global: " + Name); - Symbol *S = Symtab->addDefinedGlobal(Name); - S->setOutputIndex(Config->SyntheticGlobals.size()); - - WasmGlobal Global; - Global.Mutable = true; - Global.Type = WASM_TYPE_I32; - Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST; - Global.InitExpr.Value.Int32 = Value; - Config->SyntheticGlobals.emplace_back(S, Global); -} - // Inject a new undefined symbol into the link. This will cause the link to // fail unless this symbol can be found. static void addSyntheticUndefinedFunction(StringRef Name, @@ -284,7 +267,7 @@ static WasmSignature Signature = {{}, WASM_TYPE_NORESULT}; addSyntheticUndefinedFunction(Config->Entry, &Signature); - addSyntheticGlobal("__stack_pointer", 0); + Symtab->addDefinedGlobal("__stack_pointer", 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 @@ -20,6 +20,7 @@ #define DEBUG_TYPE "lld" using namespace llvm; +using namespace llvm::wasm; using namespace lld; using namespace lld::wasm; @@ -132,15 +133,22 @@ "\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 @@ -82,6 +82,8 @@ // space of the output object. void setOutputIndex(uint32_t Index); + void setVirtualAddress(uint32_t VA); + void update(Kind K, InputFile *F = nullptr, const WasmSymbol *Sym = nullptr, const InputSegment *Segment = nullptr, const WasmSignature *Sig = nullptr); @@ -104,6 +106,7 @@ const WasmSymbol *Sym = nullptr; const InputSegment *Segment = nullptr; llvm::Optional OutputIndex; + llvm::Optional VirtualAddress; const WasmSignature *FunctionType; }; Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -39,8 +39,12 @@ uint32_t Symbol::getVirtualAddress() const { assert(isGlobal()); DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); - if (isUndefined()) + if (isUndefined()) { + DEBUG(dbgs() << "UNDEFINED\n"); return UINT32_MAX; + } + if (VirtualAddress.hasValue()) + return VirtualAddress.getValue(); assert(Sym != nullptr); ObjFile *Obj = cast(File); @@ -57,6 +61,11 @@ return OutputIndex.getValue(); } +void Symbol::setVirtualAddress(uint32_t Value) { + DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n"); + VirtualAddress = Value; +} + void Symbol::setOutputIndex(uint32_t Index) { DEBUG(dbgs() << "setOutputIndex " << Name << " -> " << Index << "\n"); assert(!hasOutputIndex()); Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -221,10 +221,6 @@ raw_ostream &OS = Section->getStream(); writeUleb128(OS, NumGlobals, "global count"); - for (auto &Pair : Config->SyntheticGlobals) { - WasmGlobal &Global = Pair.second; - writeGlobal(OS, Global); - } if (Config->Relocatable || Config->EmitRelocs) { for (ObjFile *File : Symtab->ObjectFiles) { @@ -488,14 +484,19 @@ debugPrint("mem: global base = %d\n", Config->GlobalBase); } - createOutputSegments(); - // Static data comes first for (OutputSegment *Seg : Segments) { MemoryPtr = alignTo(MemoryPtr, Seg->Alignment); Seg->StartVA = MemoryPtr; debugPrint("mem: %-10s offset=%-8d size=%-4d align=%d\n", Seg->Name.str().c_str(), MemoryPtr, Seg->Size, Seg->Alignment); + if (Seg->Name == ".init_array") { + Symtab->addDefinedGlobal("__init_array_start", MemoryPtr); + Symtab->addDefinedGlobal("__init_array_end", MemoryPtr + Seg->Size); + } else if (Seg->Name == ".fini_array") { + Symtab->addDefinedGlobal("__fini_array_start", MemoryPtr); + Symtab->addDefinedGlobal("__fini_array_end", MemoryPtr + Seg->Size); + } MemoryPtr += Seg->Size; } @@ -512,7 +513,7 @@ debugPrint("mem: stack size = %d\n", Config->ZStackSize); debugPrint("mem: stack base = %d\n", MemoryPtr); MemoryPtr += Config->ZStackSize; - Config->SyntheticGlobals[0].second.InitExpr.Value.Int32 = MemoryPtr; + Symtab->find("__stack_pointer")->setVirtualAddress(MemoryPtr); debugPrint("mem: stack top = %d\n", MemoryPtr); } @@ -558,7 +559,7 @@ } void Writer::calculateOffsets() { - NumGlobals = Config->SyntheticGlobals.size(); + NumGlobals = 0; NumTableElems = InitialTableOffset; for (ObjFile *File : Symtab->ObjectFiles) { @@ -701,6 +702,11 @@ if (!Config->Relocatable) InitialTableOffset = 1; + createOutputSegments(); + + log("-- layoutMemory"); + layoutMemory(); + log("-- calculateTypes"); calculateTypes(); log("-- calculateImports"); @@ -721,8 +727,6 @@ log("-- assignSymbolIndexes"); assignSymbolIndexes(); - log("-- layoutMemory"); - layoutMemory(); createHeader(); log("-- createSections");