From: Sam Clegg Date: Sat, 16 Mar 2019 01:18:12 +0000 (+0000) Subject: [WebAssembly] Error on R_WASM_MEMORY_ADDR relocations against undefined data symbols. X-Git-Tag: llvmorg-10-init~9831 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=632c217921c094b983bc54b5b18e3cd9b9a7fb1a;p=platform%2Fupstream%2Fllvm.git [WebAssembly] Error on R_WASM_MEMORY_ADDR relocations against undefined data symbols. For these types of relocations an absolute memory address is required which is not possible for undefined data symbols. For symbols that can be undefined at link time (i.e. external data symbols in shared libraries) a different type of relocation (i.e. via a GOT) will be needed. Differential Revision: https://reviews.llvm.org/D59337 llvm-svn: 356310 --- diff --git a/lld/test/wasm/shared.ll b/lld/test/wasm/shared.ll index b83e61e..a40cfbe 100644 --- a/lld/test/wasm/shared.ll +++ b/lld/test/wasm/shared.ll @@ -13,10 +13,12 @@ entry: ; 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 @@ declare void @func_external() ; 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 @@ declare void @func_external() ; 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 @@ declare void @func_external() ; 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 index 0000000..8063d33 --- /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 index 42affb4..96c4736 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -66,6 +66,7 @@ private: void createCtorFunction(); void calculateInitFunctions(); + void processRelocations(InputChunk *Chunk); void assignIndexes(); void calculateImports(); void calculateExports(); @@ -1018,6 +1019,43 @@ void Writer::calculateTypes() { 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 @@ void Writer::assignIndexes() { 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());