diff --git a/lld/test/wasm/shared.ll b/lld/test/wasm/shared.ll --- a/lld/test/wasm/shared.ll +++ b/lld/test/wasm/shared.ll @@ -13,10 +13,12 @@ ; To ensure we use __stack_pointer %ptr = alloca i32 %0 = load i32, i32* @data, align 4 - %1 = load i32, i32* @data_external, align 4 - %2 = load i32 ()*, i32 ()** @indirect_func, align 4 - call i32 %2() - ret i32 %1 + ; TODO(sbc): Re-enable once the codegen supports generating the correct + ; relocation type when referencing external data in shared libraries. + ; %1 = load i32, i32* @data_external, align 4 + %1 = load i32 ()*, i32 ()** @indirect_func, align 4 + call i32 %1() + ret i32 %0 } declare void @func_external() @@ -29,7 +31,7 @@ ; CHECK: Sections: ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: dylink -; CHECK-NEXT: MemorySize: 8 +; CHECK-NEXT: MemorySize: 12 ; CHECK-NEXT: MemoryAlignment: 2 ; CHECK-NEXT: TableSize: 2 ; CHECK-NEXT: TableAlignment: 0 @@ -62,11 +64,11 @@ ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: GlobalType: I32 ; CHECK-NEXT: GlobalMutable: false -; CHECK-NEXT: - Module: env -; CHECK-NEXT: Field: data_external -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: GlobalType: I32 -; CHECK-NEXT: GlobalMutable: true +; XCHECK-NEXT: - Module: env +; XCHECK-NEXT: Field: data_external +; XCHECK-NEXT: Kind: GLOBAL +; XCHECK-NEXT: GlobalType: I32 +; XCHECK-NEXT: GlobalMutable: true ; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: func_external ; CHECK-NEXT: Kind: FUNCTION @@ -90,4 +92,4 @@ ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: GLOBAL_GET ; CHECK-NEXT: Index: 1 -; CHECK-NEXT: Content: '0000000001000000' +; CHECK-NEXT: Content: '020000000000000001000000' diff --git a/lld/test/wasm/undefined-data.ll b/lld/test/wasm/undefined-data.ll new file mode 100644 --- /dev/null +++ b/lld/test/wasm/undefined-data.ll @@ -0,0 +1,16 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: not wasm-ld -o %t.wasm %t.o 2>&1 | FileCheck %s -check-prefix=UNDEF +; RUN: not wasm-ld --allow-undefined -o %t.wasm %t.o 2>&1 | FileCheck %s -check-prefix=BADRELOC + +target triple = "wasm32-unknown-unknown" + +@data_external = external global i32 + +define i32 @_start() { +entry: + %0 = load i32, i32* @data_external, align 4 + ret i32 %0 +} + +; UNDEF: undefined symbol: data_external +; BADRELOC: undefined-data.ll.tmp.o: relocation of type R_WASM_MEMORY_ADDR_* against undefined data symbol: data_external diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -66,6 +66,7 @@ void createCtorFunction(); void calculateInitFunctions(); + void processRelocations(InputChunk *Chunk); void assignIndexes(); void calculateImports(); void calculateExports(); @@ -1018,6 +1019,43 @@ registerType(E->Signature); } +void Writer::processRelocations(InputChunk *Chunk) { + if (!Chunk->Live) + return; + ObjFile *File = Chunk->File; + ArrayRef Types = File->getWasmObj()->types(); + for (const WasmRelocation &Reloc : Chunk->getRelocations()) { + switch (Reloc.Type) { + case R_WASM_TABLE_INDEX_I32: + case R_WASM_TABLE_INDEX_SLEB: { + FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index); + if (Sym->hasTableIndex() || !Sym->hasFunctionIndex()) + continue; + Sym->setTableIndex(TableBase + IndirectFunctions.size()); + IndirectFunctions.emplace_back(Sym); + break; + } + case R_WASM_TYPE_INDEX_LEB: + // Mark target type as live + File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]); + File->TypeIsUsed[Reloc.Index] = true; + break; + case R_WASM_MEMORY_ADDR_SLEB: + case R_WASM_MEMORY_ADDR_I32: + case R_WASM_MEMORY_ADDR_LEB: { + DataSymbol *DataSym = File->getDataSymbol(Reloc.Index); + if (!Config->Relocatable && !isa(DataSym) && + !DataSym->isWeak()) + error(File->getName() + + ": relocation of type R_WASM_MEMORY_ADDR_* " + "against undefined data symbol: " + + DataSym->getName()); + break; + } + } + } +} + void Writer::assignIndexes() { assert(InputFunctions.empty()); uint32_t FunctionIndex = NumImportedFunctions; @@ -1037,36 +1075,14 @@ AddDefinedFunction(Func); } - uint32_t TableIndex = TableBase; - auto HandleRelocs = [&](InputChunk *Chunk) { - if (!Chunk->Live) - return; - ObjFile *File = Chunk->File; - ArrayRef Types = File->getWasmObj()->types(); - for (const WasmRelocation &Reloc : Chunk->getRelocations()) { - if (Reloc.Type == R_WASM_TABLE_INDEX_I32 || - Reloc.Type == R_WASM_TABLE_INDEX_SLEB) { - FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index); - if (Sym->hasTableIndex() || !Sym->hasFunctionIndex()) - continue; - Sym->setTableIndex(TableIndex++); - IndirectFunctions.emplace_back(Sym); - } else if (Reloc.Type == R_WASM_TYPE_INDEX_LEB) { - // Mark target type as live - File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]); - File->TypeIsUsed[Reloc.Index] = true; - } - } - }; - for (ObjFile *File : Symtab->ObjectFiles) { LLVM_DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n"); for (InputChunk *Chunk : File->Functions) - HandleRelocs(Chunk); + processRelocations(Chunk); for (InputChunk *Chunk : File->Segments) - HandleRelocs(Chunk); + processRelocations(Chunk); for (auto &P : File->CustomSections) - HandleRelocs(P); + processRelocations(P); } assert(InputGlobals.empty());