Index: test/wasm/relocatable.ll =================================================================== --- test/wasm/relocatable.ll +++ test/wasm/relocatable.ll @@ -159,7 +159,7 @@ ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 16 -; CHECK-NEXT: Content: FFFFFFFF +; CHECK-NEXT: Content: '00000000' ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking ; CHECK-NEXT: DataSize: 20 Index: test/wasm/weak-external.ll =================================================================== --- test/wasm/weak-external.ll +++ test/wasm/weak-external.ll @@ -1,86 +0,0 @@ -; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s -; RUN: lld -flavor wasm -strip-debug %t.o -o %t.wasm -; RUN: obj2yaml %t.wasm | FileCheck %s - -; Test that undefined weak externals (global_var) and (foo) don't cause -; link failures and resolve to zero. - -@global_var = extern_weak global i32, align 4 - -declare extern_weak i32 @foo() - -define i8* @get_address_of_foo() #0 { -entry: - ret i8* bitcast (i32 ()* @foo to i8*) -} - -define i32* @get_address_of_global_var() #0 { - ret i32* @global_var -} - -define i32 @_start() #0 { -entry: - %0 = load i32, i32* @global_var, align 4 - ret i32 %0 -} - -; CHECK: --- !WASM -; CHECK-NEXT: FileHeader: -; CHECK-NEXT: Version: 0x00000001 -; CHECK-NEXT: Sections: -; CHECK-NEXT: - Type: TYPE -; CHECK-NEXT: Signatures: -; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: ReturnType: I32 -; CHECK-NEXT: ParamTypes: -; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 0, 0 ] -; CHECK-NEXT: - Type: TABLE -; CHECK-NEXT: Tables: -; CHECK-NEXT: - ElemType: ANYFUNC -; CHECK-NEXT: Limits: -; CHECK-NEXT: Flags: [ HAS_MAX ] -; CHECK-NEXT: Initial: 0x00000002 -; CHECK-NEXT: Maximum: 0x00000002 -; CHECK-NEXT: - Type: MEMORY -; CHECK-NEXT: Memories: -; CHECK-NEXT: - Initial: 0x00000002 -; CHECK-NEXT: - Type: GLOBAL -; CHECK-NEXT: Globals: -; CHECK-NEXT: - Type: I32 -; CHECK-NEXT: Mutable: true -; CHECK-NEXT: InitExpr: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 66560 -; CHECK-NEXT: - Type: EXPORT -; CHECK-NEXT: Exports: -; 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: - Type: ELEM -; CHECK-NEXT: Segments: -; CHECK-NEXT: - Offset: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1 -; CHECK-NEXT: Functions: [ 0 ] -; CHECK-NEXT: - Type: CODE -; CHECK-NEXT: Functions: -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 4181808080000B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 41FFFFFFFF7F0B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 41002802FFFFFFFF0F0B -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 0 -; CHECK-NEXT: ... Index: test/wasm/weak-undefined.ll =================================================================== --- test/wasm/weak-undefined.ll +++ test/wasm/weak-undefined.ll @@ -0,0 +1,80 @@ +; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s +; RUN: lld -flavor wasm -strip-debug %t.o -o %t.wasm +; RUN: obj2yaml %t.wasm | FileCheck %s + +; Test that undefined weak externals (global_var) and (foo) don't cause +; link failures and resolve to zero. + +@global_var = extern_weak global i32, align 4 + +declare extern_weak i32 @foo() + +define i8* @get_address_of_foo() #0 { +entry: + ret i8* bitcast (i32 ()* @foo to i8*) +} + +define i32* @get_address_of_global_var() #0 { + ret i32* @global_var +} + +define i32 @_start() #0 { +entry: + %0 = load i32, i32* @global_var, align 4 + ret i32 %0 +} + +; CHECK: --- !WASM +; CHECK-NEXT: FileHeader: +; CHECK-NEXT: Version: 0x00000001 +; CHECK-NEXT: Sections: +; CHECK-NEXT: - Type: TYPE +; CHECK-NEXT: Signatures: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Type: FUNCTION +; CHECK-NEXT: FunctionTypes: [ 0, 0, 0 ] +; CHECK-NEXT: - Type: TABLE +; CHECK-NEXT: Tables: +; CHECK-NEXT: - ElemType: ANYFUNC +; CHECK-NEXT: Limits: +; CHECK-NEXT: Flags: [ HAS_MAX ] +; CHECK-NEXT: Initial: 0x00000001 +; CHECK-NEXT: Maximum: 0x00000001 +; CHECK-NEXT: - Type: MEMORY +; CHECK-NEXT: Memories: +; CHECK-NEXT: - Initial: 0x00000002 +; CHECK-NEXT: - Type: GLOBAL +; CHECK-NEXT: Globals: +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Type: EXPORT +; CHECK-NEXT: Exports: +; 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: - Type: CODE +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 4180808080000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 4180808080000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 4100280280808080000B +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: linking +; CHECK-NEXT: DataSize: 0 +; CHECK-NEXT: ... Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -83,7 +83,7 @@ uint32_t ObjFile::relocateTableIndex(uint32_t Original) const { Symbol *Sym = getTableSymbol(Original); - uint32_t Index = Sym->getTableIndex(); + uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0; DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original << " -> " << Index << "\n"); return Index; @@ -91,7 +91,7 @@ uint32_t ObjFile::relocateGlobalIndex(uint32_t Original) const { Symbol *Sym = getGlobalSymbol(Original); - uint32_t Index = Sym->getOutputIndex(); + uint32_t Index = Sym->hasOutputIndex() ? Sym->getOutputIndex() : 0; DEBUG(dbgs() << "relocateGlobalIndex: " << toString(*Sym) << ": " << Original << " -> " << Index << "\n"); return Index; Index: wasm/OutputSections.cpp =================================================================== --- wasm/OutputSections.cpp +++ wasm/OutputSections.cpp @@ -157,16 +157,12 @@ if (Config->EmitRelocs) NewReloc.NewIndex = calcNewIndex(File, Reloc); - else - NewReloc.NewIndex = UINT32_MAX; switch (Reloc.Type) { case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case R_WEBASSEMBLY_MEMORY_ADDR_I32: case R_WEBASSEMBLY_MEMORY_ADDR_LEB: - NewReloc.Value = File.getRelocatedAddress(Reloc.Index); - if (NewReloc.Value != UINT32_MAX) - NewReloc.Value += Reloc.Addend; + NewReloc.Value = File.getRelocatedAddress(Reloc.Index) + Reloc.Addend; break; default: NewReloc.Value = calcNewIndex(File, Reloc); Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -71,23 +71,28 @@ bool hasFunctionType() const { return FunctionType != nullptr; } const WasmSignature &getFunctionType() const; - uint32_t getOutputIndex() const; - uint32_t getTableIndex() const { return TableIndex.getValue(); } - // Returns the virtual address of a defined global. - // Only works for globals, not functions. - uint32_t getVirtualAddress() const; + uint32_t getOutputIndex() const { return OutputIndex.getValue(); } + + // Returns true if an output index has been set for this symbol + bool hasOutputIndex() const { return OutputIndex.hasValue(); } // Set the output index of the symbol (in the function or global index // space of the output object. void setOutputIndex(uint32_t Index); + uint32_t getTableIndex() const { return TableIndex.getValue(); } + // Returns true if a table index has been set for this symbol bool hasTableIndex() const { return TableIndex.hasValue(); } // Set the table index of the symbol void setTableIndex(uint32_t Index); + // Returns the virtual address of a defined global. + // Only works for globals, not functions. + uint32_t getVirtualAddress() const; + void setVirtualAddress(uint32_t VA); void update(Kind K, InputFile *F = nullptr, const WasmSymbol *Sym = nullptr, Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -40,7 +40,7 @@ assert(isGlobal()); DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); if (isUndefined()) - return UINT32_MAX; + return 0; if (VirtualAddress.hasValue()) return VirtualAddress.getValue(); @@ -53,12 +53,6 @@ return Segment->translateVA(Global.InitExpr.Value.Int32); } -uint32_t Symbol::getOutputIndex() const { - if (isUndefined() && isWeak()) - return 0; - return OutputIndex.getValue(); -} - void Symbol::setVirtualAddress(uint32_t Value) { DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n"); assert(!VirtualAddress.hasValue()); Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -629,12 +629,14 @@ Sym->setOutputIndex(GlobalIndex++); } } + } + for (ObjFile *File : Symtab->ObjectFiles) { for (Symbol *Sym : File->getTableSymbols()) { - if (!Sym->hasTableIndex()) { - Sym->setTableIndex(TableIndex++); - IndirectFunctions.emplace_back(Sym); - } + if (Sym->hasTableIndex() || !Sym->hasOutputIndex()) + continue; + Sym->setTableIndex(TableIndex++); + IndirectFunctions.emplace_back(Sym); } } }