--- /dev/null
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
+# RUN: wasm-ld --experimental-pic -shared -o %t.wasm %t.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+# RUN: llvm-objdump -d %t.wasm | FileCheck %s -check-prefix=ASM
+
+# Verify the weakly defined fuctions (weak_func) are both
+# imported and exported, and that internal usage (direct call)
+# always uses the imported version.
+
+
+.globl weak_func
+.weak weak_func
+weak_func:
+ .functype weak_func () -> (i32)
+ i32.const 0
+ end_function
+
+.globl call_weak
+call_weak:
+# ASM: <call_weak>:
+ .functype call_weak () -> (i32)
+ call weak_func
+# ASM: 10 80 80 80 80 00 call 0
+ end_function
+# ASM-NEXT: 0b end
+
+# CHECK: - Type: IMPORT
+# CHECK-NEXT: Imports:
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: memory
+# CHECK-NEXT: Kind: MEMORY
+# CHECK-NEXT: Memory:
+# CHECK-NEXT: Minimum: 0x0
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __memory_base
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: false
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __table_base
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: false
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: weak_func
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: SigIndex: 0
+
+# CHECK: - Type: CUSTOM
+# CHECK-NEXT: Name: name
+# CHECK-NEXT: FunctionNames:
+# CHECK-NEXT: - Index: 0
+# CHECK-NEXT: Name: weak_func
+# CHECK-NEXT: - Index: 1
+# CHECK-NEXT: Name: __wasm_call_ctors
+# CHECK-NEXT: - Index: 2
+# CHECK-NEXT: Name: __wasm_apply_data_relocs
+# CHECK-NEXT: - Index: 3
+# CHECK-NEXT: Name: weak_func
}
bool Symbol::isExported() const {
+ // Shared libraries must export all weakly defined symbols
+ // in case they contain the version that will be chosed by
+ // the dynamic linker.
+ if (config->shared && isLive() && isDefined() && isWeak())
+ return true;
+
if (!isDefined() || isLocal())
return false;
}
uint32_t FunctionSymbol::getFunctionIndex() const {
- if (auto *f = dyn_cast<DefinedFunction>(this))
- return f->function->getFunctionIndex();
- if (const auto *u = dyn_cast<UndefinedFunction>(this)) {
- if (u->stubFunction) {
+ if (const auto *u = dyn_cast<UndefinedFunction>(this))
+ if (u->stubFunction)
return u->stubFunction->getFunctionIndex();
- }
- }
- assert(functionIndex != INVALID_INDEX);
- return functionIndex;
+ if (functionIndex != INVALID_INDEX)
+ return functionIndex;
+ auto *f = cast<DefinedFunction>(this);
+ return f->function->getFunctionIndex();
}
void FunctionSymbol::setFunctionIndex(uint32_t index) {
function ? &function->signature : nullptr),
function(function) {}
+uint32_t DefinedFunction::getExportedFunctionIndex() const {
+ return function->getFunctionIndex();
+}
+
uint64_t DefinedData::getVA() const {
LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n");
if (segment)
return s->kind() == DefinedFunctionKind;
}
+ // Get the function index to be used when exporting. This only applies to
+ // defined functions and can be differ from the regular function index for
+ // weakly defined functions (that are imported and used via one index but
+ // defined and exported via another).
+ uint32_t getExportedFunctionIndex() const;
+
InputFunction *function;
};
writeUleb128(sub.os, flags, "sym flags");
if (auto *f = dyn_cast<FunctionSymbol>(sym)) {
- writeUleb128(sub.os, f->getFunctionIndex(), "index");
+ if (auto *d = dyn_cast<DefinedFunction>(sym)) {
+ writeUleb128(sub.os, d->getExportedFunctionIndex(), "index");
+ } else {
+ writeUleb128(sub.os, f->getFunctionIndex(), "index");
+ }
if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
writeStr(sub.os, sym->getName(), "sym name");
} else if (auto *g = dyn_cast<GlobalSymbol>(sym)) {
}
static bool shouldImport(Symbol *sym) {
- if (!sym->isUndefined())
- return false;
- if (sym->isWeak() && !config->relocatable && !config->isPic)
+ // We don't generate imports for data symbols. They however can be imported
+ // as GOT entries.
+ if (isa<DataSymbol>(sym))
return false;
if (!sym->isLive())
return false;
if (!sym->isUsedInRegularObj)
return false;
- // We don't generate imports for data symbols. They however can be imported
- // as GOT entries.
- if (isa<DataSymbol>(sym))
+ // When a symbol is weakly defined in a shared library we need to allow
+ // it to be overridden by another module so need to both import
+ // and export the symbol.
+ if (config->shared && sym->isDefined() && sym->isWeak())
+ return true;
+ if (!sym->isUndefined())
+ return false;
+ if (sym->isWeak() && !config->relocatable && !config->isPic)
return false;
// In PIC mode we only need to import functions when they are called directly.
if (Optional<StringRef> exportName = f->function->getExportName()) {
name = *exportName;
}
- export_ = {name, WASM_EXTERNAL_FUNCTION, f->getFunctionIndex()};
+ export_ = {name, WASM_EXTERNAL_FUNCTION, f->getExportedFunctionIndex()};
} else if (auto *g = dyn_cast<DefinedGlobal>(sym)) {
if (g->getGlobalType()->Mutable && !g->getFile() && !g->forceExport) {
// Avoid exporting mutable globals are linker synthesized (e.g.