; CHECK-NEXT: - Name: memory
; CHECK-NEXT: Kind: MEMORY
; CHECK-NEXT: Index: 0
-; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: - Name: start_alias
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 0
-; CHECK-NEXT: - Name: start_alias
+; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 0
; CHECK-NEXT: - Name: __heap_base
; 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: - Name: bar
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 0
; CHECK-NEXT: - Name: foo
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: call_ptr
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 4
; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o
-; RUN: lld -flavor wasm -e entry -o %t.wasm %t.o
-; RUN: obj2yaml %t.wasm | FileCheck %s
-; RUN: lld -flavor wasm --entry=entry -o %t.wasm %t.o
-; RUN: obj2yaml %t.wasm | FileCheck %s
-define void @entry() local_unnamed_addr #0 {
+define hidden void @entry() local_unnamed_addr #0 {
entry:
ret void
}
-; CHECK: - Type: EXPORT
-; CHECK: Exports:
-; CHECK: - Name: memory
-; CHECK: Kind: MEMORY
-; CHECK: Index: 0
-; CHECK: - Name: entry
-; CHECK: Kind: FUNCTION
-; CHECK: Index: 0
+; RUN: lld -flavor wasm -e entry -o %t1.wasm %t.o
+; RUN: obj2yaml %t1.wasm | FileCheck %s
+; RUN: lld -flavor wasm --entry=entry -o %t2.wasm %t.o
+; RUN: obj2yaml %t2.wasm | FileCheck %s
+
+; CHECK: - Type: EXPORT
+; CHECK-NEXT: Exports:
+; CHECK-NEXT: - Name: memory
+; CHECK-NEXT: Kind: MEMORY
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: entry
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 0
+
+; The __wasm_call_ctors is somewhat special. Make sure we can use it
+; as the entry point if we choose
+; RUN: lld -flavor wasm --entry=__wasm_call_ctors -o %t3.wasm %t.o
+; RUN: obj2yaml %t3.wasm | FileCheck %s -check-prefix=CHECK-CTOR
+
+; CHECK-CTOR: - Type: EXPORT
+; CHECK-CTOR-NEXT: Exports:
+; CHECK-CTOR-NEXT: - Name: memory
+; CHECK-CTOR-NEXT: Kind: MEMORY
+; CHECK-CTOR-NEXT: Index: 0
+; CHECK-CTOR-NEXT: - Name: __wasm_call_ctors
+; CHECK-CTOR-NEXT: Kind: FUNCTION
+; CHECK-CTOR-NEXT: Index: 1
; CHECK-NEXT: - Name: memory
; CHECK-NEXT: Kind: MEMORY
; CHECK-NEXT: Index: 0
-; CHECK-NEXT: - Name: _start
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: hidden_function
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: __heap_base
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 1
; 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: - Name: __wasm_call_ctors
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 0
; CHECK-NEXT: - Name: __stack_pointer
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 0
; 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: objectDefault
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: archiveDefault
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 4
; CHECK-NEXT: - Name: memory
; CHECK-NEXT: Kind: MEMORY
; CHECK-NEXT: Index: 0
-; CHECK-NEXT: - Name: _start
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: alias_fn
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: direct_fn
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 2
; 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: get_address_of_foo
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 0
; CHECK-NEXT: - Name: get_address_of_global_var
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: __heap_base
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 1
if (Config->Relocatable && Args.hasArg(OPT_undefined))
error("undefined symbols specified for relocatable output file");
+ Symbol *EntrySym = nullptr;
if (!Config->Relocatable) {
static WasmSignature Signature = {{}, WASM_TYPE_NORESULT};
if (!Config->Entry.empty())
- Symtab->addUndefinedFunction(Config->Entry, &Signature);
+ EntrySym = Symtab->addUndefinedFunction(Config->Entry, &Signature);
// Handle the `--undefined <sym>` options.
for (auto* Arg : Args.filtered(OPT_undefined))
Sym->setHidden(false);
}
+ if (EntrySym)
+ EntrySym->setHidden(false);
+
if (errorCount())
return;
S->setFunctionType(Type);
} else if (!S->isFunction()) {
error("symbol type mismatch: " + Name);
+ } else if (!S->isDefined()) {
+ DEBUG(dbgs() << "resolving existing undefined function: " << Name << "\n");
+ S->update(Symbol::DefinedFunctionKind, nullptr, Flags);
}
return S;
}
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
- if (WasInserted)
+ if (WasInserted) {
S->update(Symbol::DefinedGlobalKind);
- else if (!S->isGlobal())
+ } else if (!S->isGlobal()) {
error("symbol type mismatch: " + Name);
+ } else {
+ DEBUG(dbgs() << "resolving existing undefined global: " << Name << "\n");
+ S->update(Symbol::DefinedGlobalKind);
+ }
return S;
}
}
void Symbol::setHidden(bool IsHidden) {
+ DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n");
Flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
if (IsHidden)
Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
}
void Writer::calculateExports() {
- Symbol *EntrySym = Symtab->find(Config->Entry);
- bool ExportEntry = !Config->Relocatable && EntrySym && EntrySym->isDefined();
bool ExportHidden = Config->EmitRelocs;
StringSet<> UsedNames;
auto BudgeLocalName = [&](const Symbol *Sym) {
}
};
- if (ExportEntry)
- ExportedSymbols.emplace_back(WasmExportEntry{EntrySym, EntrySym->getName()});
-
- if (Config->CtorSymbol && ExportHidden &&
- !(ExportEntry && Config->CtorSymbol == EntrySym))
+ if (Config->CtorSymbol && (!Config->CtorSymbol->isHidden() || ExportHidden))
ExportedSymbols.emplace_back(
WasmExportEntry{Config->CtorSymbol, Config->CtorSymbol->getName()});
if ((Sym->isHidden() || Sym->isLocal()) && !ExportHidden)
continue;
- if (ExportEntry && Sym == EntrySym)
- continue;
ExportedSymbols.emplace_back(WasmExportEntry{Sym, BudgeLocalName(Sym)});
}
}