diff --git a/lld/test/wasm/startstop.ll b/lld/test/wasm/startstop.ll new file mode 100644 --- /dev/null +++ b/lld/test/wasm/startstop.ll @@ -0,0 +1,57 @@ +; RUN: llc -filetype=obj -o %t.o %s +; RUN: wasm-ld --no-gc-sections %t.o -o %t.wasm +; RUN: obj2yaml %t.wasm | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +@foo = global i32 3, section "mysection", align 4 +@bar = global i32 4, section "mysection", align 4 + +@__start_mysection = external global i8* +@__stop_mysection = external global i8* + +define i8** @get_start() { + ret i8** @__start_mysection +} + +define i8** @get_end() { + ret i8** @__stop_mysection +} + +define void @_start() { +entry: + ret void +} +; CHECK: - Type: CODE +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: [] +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: [] +; CHECK-NEXT: Body: 4180888080000B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: [] +; CHECK-NEXT: Body: 4188888080000B +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: [] +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Type: DATA +; CHECK-NEXT: Segments: +; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: InitFlags: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Content: '0300000004000000' +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: get_start +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: get_end +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: _start diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -608,10 +608,6 @@ // Add synthetic dummies for weak undefined functions. Must happen // after LTO otherwise functions may not yet have signatures. Symtab->handleWeakUndefines(); - - // Make sure we have resolved all symbols. - if (!Config->AllowUndefined) - Symtab->reportRemainingUndefines(); } if (EntrySym) diff --git a/lld/wasm/SymbolTable.h b/lld/wasm/SymbolTable.h --- a/lld/wasm/SymbolTable.h +++ b/lld/wasm/SymbolTable.h @@ -81,6 +81,8 @@ InputGlobal *Global); DefinedFunction *addSyntheticFunction(StringRef Name, uint32_t Flags, InputFunction *Function); + DefinedData *addOptionalDataSymbol(StringRef Name, uint32_t Value, + uint32_t Flags); void handleSymbolVariants(); void handleWeakUndefines(); diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -198,6 +198,17 @@ Flags, nullptr, Function); } +DefinedData *SymbolTable::addOptionalDataSymbol(StringRef Name, uint32_t Value, + uint32_t Flags) { + Symbol *S = find(Name); + if (!S || S->isDefined()) + return nullptr; + LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << Name << "\n"); + auto *rtn = replaceSymbol(S, Name, Flags); + rtn->setVirtualAddress(Value); + return rtn; +} + DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name, uint32_t Flags) { LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n"); diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -73,6 +73,8 @@ void addSection(OutputSection *Sec); void addSections(); + void addStartStopSymbols(const InputSegment *Seg); + void createCustomSections(); void createSyntheticSections(); void finalizeSections(); @@ -293,6 +295,22 @@ OutputSections.push_back(Sec); } +// If a section name is valid as a C identifier (which is rare because of +// the leading '.'), linkers are expected to define __start_ and +// __stop_ symbols. They are at beginning and end of the section, +// respectively. This is not requested by the ELF standard, but GNU ld and +// gold provide the feature, and used by many programs. +void Writer::addStartStopSymbols(const InputSegment *Seg) { + StringRef S = Seg->getName(); + LLVM_DEBUG(dbgs() << "addStartStopSymbols: " << S << "\n"); + if (!isValidCIdentifier(S)) + return; + uint32_t Start = Seg->OutputSeg->StartVA + Seg->OutputSegmentOffset; + uint32_t Stop = Start + Seg->getSize(); + Symtab->addOptionalDataSymbol(Saver.save("__start_" + S), Start, 0); + Symtab->addOptionalDataSymbol(Saver.save("__stop_" + S), Stop, 0); +} + void Writer::addSections() { addSection(Out.DylinkSec); addSection(Out.TypeSec); @@ -543,8 +561,6 @@ Out.FunctionSec->addFunction(Func); } - scanRelocations(); - for (InputGlobal *Global : Symtab->SyntheticGlobals) Out.GlobalSec->addGlobal(Global); @@ -724,19 +740,40 @@ populateTargetFeatures(); log("-- calculateImports"); calculateImports(); + log("-- layoutMemory"); + layoutMemory(); + + if (!Config->Relocatable) { + // Create linker synthesized __start_SECNAME/__stop_SECNAME symbols + // This has to be done after memory layout is performed. + for (const OutputSegment *Seg : Segments) + for (const InputSegment *S : Seg->InputSegments) + addStartStopSymbols(S); + } + log("-- assignIndexes"); assignIndexes(); + log("-- scanRelocations"); + scanRelocations(); log("-- calculateInitFunctions"); calculateInitFunctions(); - log("-- calculateTypes"); - calculateTypes(); - log("-- layoutMemory"); - layoutMemory(); + if (!Config->Relocatable) { + // Create linker synthesized functions if (Config->Pic) createApplyRelocationsFunction(); createCallCtorsFunction(); + + // Make sure we have resolved all symbols. + if (!Config->AllowUndefined) + Symtab->reportRemainingUndefines(); + + if (errorCount()) + return; } + + log("-- calculateTypes"); + calculateTypes(); log("-- calculateExports"); calculateExports(); log("-- calculateCustomSections");