diff --git a/lld/test/wasm/locals-duplicate.test b/lld/test/wasm/locals-duplicate.test --- a/lld/test/wasm/locals-duplicate.test +++ b/lld/test/wasm/locals-duplicate.test @@ -231,17 +231,19 @@ ; RELOC-NEXT: ParamTypes: [] ; RELOC-NEXT: ReturnTypes: ; RELOC-NEXT: - I32 +; RELOC-NEXT: - Type: IMPORT +; RELOC-NEXT: Imports: +; RELOC-NEXT: - Module: env +; RELOC-NEXT: Field: __indirect_function_table +; RELOC-NEXT: Kind: TABLE +; RELOC-NEXT: Table: +; RELOC-NEXT: Index: 0 +; RELOC-NEXT: ElemType: FUNCREF +; RELOC-NEXT: Limits: +; RELOC-NEXT: Initial: 0x3 ; RELOC-NEXT: - Type: FUNCTION ; RELOC-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; RELOC-NEXT: 0, 0 ] -; RELOC-NEXT: - Type: TABLE -; RELOC-NEXT: Tables: -; RELOC-NEXT: - Index: 0 -; RELOC-NEXT: ElemType: FUNCREF -; RELOC-NEXT: Limits: -; RELOC-NEXT: Flags: [ HAS_MAX ] -; RELOC-NEXT: Initial: 0x7 -; RELOC-NEXT: Maximum: 0x7 ; RELOC-NEXT: - Type: MEMORY ; RELOC-NEXT: Memories: ; RELOC-NEXT: - Initial: 0x1 @@ -412,7 +414,7 @@ ; RELOC-NEXT: - Index: 8 ; RELOC-NEXT: Kind: TABLE ; RELOC-NEXT: Name: __indirect_function_table -; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Flags: [ UNDEFINED, NO_STRIP ] ; RELOC-NEXT: Table: 0 ; RELOC-NEXT: - Index: 9 ; RELOC-NEXT: Kind: FUNCTION diff --git a/lld/test/wasm/relocatable.ll b/lld/test/wasm/relocatable.ll --- a/lld/test/wasm/relocatable.ll +++ b/lld/test/wasm/relocatable.ll @@ -1,7 +1,10 @@ ; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/hello.s -o %t.hello.o ; RUN: llc -filetype=obj %s -o %t.o -; RUN: wasm-ld -r -o %t.wasm %t.hello.o %t.o -; RUN: obj2yaml %t.wasm | FileCheck %s +; RUN: wasm-ld -r -o %t2.o %t.hello.o %t.o +; RUN: obj2yaml %t2.o | FileCheck %s + +; Verify the resulting object can be used as linker input +; RUN: wasm-ld --allow-undefined -o %t.wasm %t2.o --export-table target triple = "wasm32-unknown-unknown" @@ -32,6 +35,11 @@ ; Test that __attribute__(used) (i.e NO_STRIP) is preserved in the relocated symbol table @llvm.used = appending global [1 x i8*] [i8* bitcast (i32 ()* @my_func to i8*)], section "llvm.metadata" +define void @_start() { + ret void +} + + ; CHECK: --- !WASM ; CHECK-NEXT: FileHeader: ; CHECK-NEXT: Version: 0x1 @@ -63,16 +71,16 @@ ; CHECK-NEXT: Field: bar_import ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Table: +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: ElemType: FUNCREF +; CHECK-NEXT: Limits: +; CHECK-NEXT: Initial: 0x3 ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 2, 1, 1 ] -; CHECK-NEXT: - Type: TABLE -; CHECK-NEXT: Tables: -; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: ElemType: FUNCREF -; CHECK-NEXT: Limits: -; CHECK-NEXT: Flags: [ HAS_MAX ] -; CHECK-NEXT: Initial: 0x4 -; CHECK-NEXT: Maximum: 0x4 +; CHECK-NEXT: FunctionTypes: [ 2, 1, 1, 2 ] ; CHECK-NEXT: - Type: MEMORY ; CHECK-NEXT: Memories: ; CHECK-NEXT: - Initial: 0x1 diff --git a/lld/test/wasm/signature-mismatch.ll b/lld/test/wasm/signature-mismatch.ll --- a/lld/test/wasm/signature-mismatch.ll +++ b/lld/test/wasm/signature-mismatch.ll @@ -82,7 +82,7 @@ ; RELOC-NEXT: - Index: 3 ; RELOC-NEXT: Kind: TABLE ; RELOC-NEXT: Name: __indirect_function_table -; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Flags: [ UNDEFINED, NO_STRIP ] ; RELOC-NEXT: Table: 0 ; RELOC-NEXT: - Index: 4 ; RELOC-NEXT: Kind: FUNCTION diff --git a/lld/test/wasm/weak-alias.ll b/lld/test/wasm/weak-alias.ll --- a/lld/test/wasm/weak-alias.ll +++ b/lld/test/wasm/weak-alias.ll @@ -149,16 +149,16 @@ ; RELOC-NEXT: Kind: GLOBAL ; RELOC-NEXT: GlobalType: I32 ; RELOC-NEXT: GlobalMutable: true +; RELOC-NEXT: - Module: env +; RELOC-NEXT: Field: __indirect_function_table +; RELOC-NEXT: Kind: TABLE +; RELOC-NEXT: Table: +; RELOC-NEXT: Index: 0 +; RELOC-NEXT: ElemType: FUNCREF +; RELOC-NEXT: Limits: +; RELOC-NEXT: Initial: 0x1 ; RELOC-NEXT: - Type: FUNCTION ; RELOC-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1, 1 ] -; RELOC-NEXT: - Type: TABLE -; RELOC-NEXT: Tables: -; RELOC-NEXT: - Index: 0 -; RELOC-NEXT: ElemType: FUNCREF -; RELOC-NEXT: Limits: -; RELOC-NEXT: Flags: [ HAS_MAX ] -; RELOC-NEXT: Initial: 0x2 -; RELOC-NEXT: Maximum: 0x2 ; RELOC-NEXT: - Type: MEMORY ; RELOC-NEXT: Memories: ; RELOC-NEXT: - Initial: 0x0 @@ -279,7 +279,7 @@ ; RELOC-NEXT: - Index: 8 ; RELOC-NEXT: Kind: TABLE ; RELOC-NEXT: Name: __indirect_function_table -; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Flags: [ UNDEFINED, NO_STRIP ] ; RELOC-NEXT: Table: 0 ; RELOC-NEXT: - Type: CUSTOM ; RELOC-NEXT: Name: name diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -817,22 +817,31 @@ } static TableSymbol *resolveIndirectFunctionTable() { - // Even though we may not need a table, if the user explicitly specified - // --import-table or --export-table, ensure a table is residualized. - if (config->importTable) - return createUndefinedIndirectFunctionTable(functionTableName); - if (config->exportTable) - return createDefinedIndirectFunctionTable(functionTableName); - - // Otherwise, check to the symtab to find the indirect function table. - if (Symbol *sym = symtab->find(functionTableName)) { - if (sym->isLive()) { - if (auto *t = dyn_cast(sym)) { - return t->isDefined() - ? t - : createDefinedIndirectFunctionTable(functionTableName); - } + Symbol *existingTable = symtab->find(functionTableName); + if (existingTable) { + if (!isa(existingTable)) { + error(Twine("reserved symbol must be of type table: `") + + functionTableName + "`"); + return nullptr; } + if (existingTable->isDefined()) { + error(Twine("reserved symbol must not be defined in input files: `") + + functionTableName + "`"); + return nullptr; + } + } + + if (config->importTable) { + if (existingTable) + return cast(existingTable); + else + return createUndefinedIndirectFunctionTable(functionTableName); + } else if ((existingTable && existingTable->isLive()) || + config->exportTable) { + // A defined table is required. Either because the user request an exported + // table or because the table symbol is already live. The existing table is + // guaranteed to be undefined due to the check above. + return createDefinedIndirectFunctionTable(functionTableName); } // An indirect function table will only be present in the symbol table if @@ -1029,11 +1038,13 @@ // Do size optimizations: garbage collection markLive(); - // Provide the indirect funciton table if needed. - WasmSym::indirectFunctionTable = resolveIndirectFunctionTable(); + if (!config->relocatable) { + // Provide the indirect funciton table if needed. + WasmSym::indirectFunctionTable = resolveIndirectFunctionTable(); - if (errorCount()) - return; + if (errorCount()) + return; + } // Write the result to the file. writeResult();