[WebAssembly] Update to match llvm changes to TABLE relocations

TABLE relocations now store the function that is being refered
to indirectly.

See rL323165.

Also extend the call-indirect.ll a little.

Based on a patch by Nicholas Wilson!

llvm-svn: 323168
This commit is contained in:
Sam Clegg 2018-01-23 01:25:56 +00:00
parent ac904d0e3a
commit ab604a9882
9 changed files with 80 additions and 71 deletions

View File

@ -1,17 +1,18 @@
@indirect_bar = internal local_unnamed_addr global i32 ()* @bar, align 4 @indirect_bar = internal local_unnamed_addr global i64 ()* @bar, align 4
@indirect_foo = internal local_unnamed_addr global i32 ()* @foo, align 4 @indirect_foo = internal local_unnamed_addr global i32 ()* @foo, align 4
declare i32 @foo() local_unnamed_addr declare i32 @foo() local_unnamed_addr
define i32 @bar() { define i64 @bar() {
entry: entry:
ret i32 1 ret i64 1
} }
define void @call_bar_indirect() local_unnamed_addr #1 { define void @call_bar_indirect() local_unnamed_addr #1 {
entry: entry:
%0 = load i32 ()*, i32 ()** @indirect_bar, align 4 %0 = load i64 ()*, i64 ()** @indirect_bar, align 4
%1 = load i32 ()*, i32 ()** @indirect_foo, align 4 %1 = load i32 ()*, i32 ()** @indirect_foo, align 4
%call = tail call i32 %0() #2 %call0 = tail call i64 %0() #2
%call1 = tail call i32 %1() #2
ret void ret void
} }

View File

@ -38,21 +38,24 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: - Type: TYPE ; CHECK-NEXT: - Type: TYPE
; CHECK-NEXT: Signatures: ; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ReturnType: I64
; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: - Index: 2
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I32 ; CHECK-NEXT: - I32
; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: - Index: 4
; CHECK-NEXT: ReturnType: I64 ; CHECK-NEXT: ReturnType: I64
; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I64 ; CHECK-NEXT: - I64
; CHECK-NEXT: - Type: FUNCTION ; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 2, 1 ] ; CHECK-NEXT: FunctionTypes: [ 0, 1, 2, 2, 3, 1 ]
; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables: ; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC ; CHECK-NEXT: - ElemType: ANYFUNC
@ -110,19 +113,21 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: Functions: ; CHECK-NEXT: Functions:
; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Locals: ; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41010B ; CHECK-NEXT: Body: 42010B
; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Locals: ; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 410028028088808000118080808000001A0B ; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Count: 1
; CHECK-NEXT: Body: 4100280284888080002100410028028088808000118080808000001A2000118280808000001A0B
; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Locals: ; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41020B ; CHECK-NEXT: Body: 41020B
; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: - Index: 3
; CHECK-NEXT: Locals: ; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 410028028888808000118080808000001A41000B ; CHECK-NEXT: Body: 410028028888808000118280808000001A41000B
; CHECK-NEXT: - Index: 4 ; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Locals: ; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 42012000118380808000001A0B ; CHECK-NEXT: Body: 42012000118480808000001A0B
; CHECK-NEXT: - Index: 5 ; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Locals: ; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B ; CHECK-NEXT: Body: 0B

View File

@ -385,13 +385,13 @@
; RELOC-NEXT: Index: 5 ; RELOC-NEXT: Index: 5
; RELOC-NEXT: Offset: 0x0000006A ; RELOC-NEXT: Offset: 0x0000006A
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB ; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
; RELOC-NEXT: Index: 3 ; RELOC-NEXT: Index: 9
; RELOC-NEXT: Offset: 0x00000073 ; RELOC-NEXT: Offset: 0x00000073
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB ; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
; RELOC-NEXT: Index: 4 ; RELOC-NEXT: Index: 10
; RELOC-NEXT: Offset: 0x0000007C ; RELOC-NEXT: Offset: 0x0000007C
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB ; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
; RELOC-NEXT: Index: 5 ; RELOC-NEXT: Index: 11
; RELOC-NEXT: Offset: 0x00000085 ; RELOC-NEXT: Offset: 0x00000085
; RELOC-NEXT: Functions: ; RELOC-NEXT: Functions:
; RELOC-NEXT: - Index: 0 ; RELOC-NEXT: - Index: 0

View File

@ -177,7 +177,7 @@ entry:
; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Relocations: ; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
; CHECK-NEXT: Index: 0 ; CHECK-NEXT: Index: 4
; CHECK-NEXT: Offset: 0x00000012 ; CHECK-NEXT: Offset: 0x00000012
; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Index: 1

View File

@ -48,23 +48,19 @@ static void applyRelocation(uint8_t *Buf, const OutputRelocation &Reloc) {
switch (Reloc.Reloc.Type) { switch (Reloc.Reloc.Type) {
case R_WEBASSEMBLY_TYPE_INDEX_LEB: case R_WEBASSEMBLY_TYPE_INDEX_LEB:
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
ExistingValue = decodeULEB128(Buf); ExistingValue = decodeULEB128(Buf);
// Additional check to verify that the existing value that the location
// matches our expectations.
if (ExistingValue != Reloc.Reloc.Index) { if (ExistingValue != Reloc.Reloc.Index) {
DEBUG(dbgs() << "existing value: " << decodeULEB128(Buf) << "\n"); DEBUG(dbgs() << "existing value: " << decodeULEB128(Buf) << "\n");
assert(decodeULEB128(Buf) == Reloc.Reloc.Index); assert(decodeULEB128(Buf) == Reloc.Reloc.Index);
} }
LLVM_FALLTHROUGH; LLVM_FALLTHROUGH;
case R_WEBASSEMBLY_MEMORY_ADDR_LEB: case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
encodeULEB128(Reloc.Value, Buf, 5); encodeULEB128(Reloc.Value, Buf, 5);
break; break;
case R_WEBASSEMBLY_TABLE_INDEX_SLEB: case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
ExistingValue = decodeSLEB128(Buf);
if (ExistingValue != Reloc.Reloc.Index) {
DEBUG(dbgs() << "existing value: " << decodeSLEB128(Buf) << "\n");
assert(decodeSLEB128(Buf) == Reloc.Reloc.Index);
}
LLVM_FALLTHROUGH;
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
encodeSLEB128(static_cast<int32_t>(Reloc.Value), Buf, 5); encodeSLEB128(static_cast<int32_t>(Reloc.Value), Buf, 5);
break; break;
@ -111,17 +107,7 @@ void InputChunk::calcRelocations() {
if (Config->Relocatable) if (Config->Relocatable)
NewReloc.NewIndex = File->calcNewIndex(Reloc); NewReloc.NewIndex = File->calcNewIndex(Reloc);
switch (Reloc.Type) { NewReloc.Value = File->calcNewValue(Reloc);
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
NewReloc.Value = File->getRelocatedAddress(Reloc.Index) + Reloc.Addend;
break;
default:
NewReloc.Value = File->calcNewIndex(Reloc);
break;
}
OutRelocations.emplace_back(NewReloc); OutRelocations.emplace_back(NewReloc);
} }
} }

View File

@ -46,6 +46,7 @@ public:
} }
uint32_t getOutputOffset() const { return OutputOffset; } uint32_t getOutputOffset() const { return OutputOffset; }
ArrayRef<WasmRelocation> getRelocations() const { return Relocations; }
virtual StringRef getComdat() const = 0; virtual StringRef getComdat() const = 0;

View File

@ -47,11 +47,10 @@ void ObjFile::dumpInfo() const {
" Total Functions : " + Twine(FunctionSymbols.size()) + "\n" + " Total Functions : " + Twine(FunctionSymbols.size()) + "\n" +
" Total Globals : " + Twine(GlobalSymbols.size()) + "\n" + " Total Globals : " + Twine(GlobalSymbols.size()) + "\n" +
" Function Imports : " + Twine(NumFunctionImports) + "\n" + " Function Imports : " + Twine(NumFunctionImports) + "\n" +
" Global Imports : " + Twine(NumGlobalImports) + "\n" + " Global Imports : " + Twine(NumGlobalImports) + "\n");
" Table Entries : " + Twine(TableSymbols.size()) + "\n");
} }
uint32_t ObjFile::getRelocatedAddress(uint32_t GlobalIndex) const { uint32_t ObjFile::relocateVirtualAddress(uint32_t GlobalIndex) const {
return GlobalSymbols[GlobalIndex]->getVirtualAddress(); return GlobalSymbols[GlobalIndex]->getVirtualAddress();
} }
@ -68,7 +67,7 @@ uint32_t ObjFile::relocateTypeIndex(uint32_t Original) const {
} }
uint32_t ObjFile::relocateTableIndex(uint32_t Original) const { uint32_t ObjFile::relocateTableIndex(uint32_t Original) const {
Symbol *Sym = TableSymbols[Original]; Symbol *Sym = FunctionSymbols[Original];
uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0; uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0;
DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original
<< " -> " << Index << "\n"); << " -> " << Index << "\n");
@ -92,10 +91,9 @@ uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const {
case R_WEBASSEMBLY_TYPE_INDEX_LEB: case R_WEBASSEMBLY_TYPE_INDEX_LEB:
return relocateTypeIndex(Reloc.Index); return relocateTypeIndex(Reloc.Index);
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
return relocateFunctionIndex(Reloc.Index);
case R_WEBASSEMBLY_TABLE_INDEX_I32: case R_WEBASSEMBLY_TABLE_INDEX_I32:
case R_WEBASSEMBLY_TABLE_INDEX_SLEB: case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
return relocateTableIndex(Reloc.Index); return relocateFunctionIndex(Reloc.Index);
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB: case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
@ -106,6 +104,27 @@ uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const {
} }
} }
// Translate from the relocation's index into the final linked output value.
uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const {
switch (Reloc.Type) {
case R_WEBASSEMBLY_TABLE_INDEX_I32:
case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
return relocateTableIndex(Reloc.Index);
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
return relocateVirtualAddress(Reloc.Index) + Reloc.Addend;
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
return relocateTypeIndex(Reloc.Index);
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
return relocateFunctionIndex(Reloc.Index);
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
return relocateGlobalIndex(Reloc.Index);
default:
llvm_unreachable("unknown relocation type");
}
}
void ObjFile::parse() { void ObjFile::parse() {
// Parse a memory buffer as a wasm file. // Parse a memory buffer as a wasm file.
DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n"); DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n");
@ -271,24 +290,6 @@ void ObjFile::initializeSymbols() {
for (size_t I = 0; I < GlobalSymbols.size(); ++I) for (size_t I = 0; I < GlobalSymbols.size(); ++I)
assert(GlobalSymbols[I] != nullptr);); assert(GlobalSymbols[I] != nullptr););
// Populate `TableSymbols` with all symbols that are called indirectly
uint32_t SegmentCount = WasmObj->elements().size();
if (SegmentCount) {
if (SegmentCount > 1)
fatal(getName() + ": contains more than one element segment");
const WasmElemSegment &Segment = WasmObj->elements()[0];
if (Segment.Offset.Opcode != WASM_OPCODE_I32_CONST)
fatal(getName() + ": unsupported element segment");
if (Segment.TableIndex != 0)
fatal(getName() + ": unsupported table index in elem segment");
uint32_t Offset = Segment.Offset.Value.Int32;
TableSymbols.resize(Offset);
TableSymbols.reserve(Offset + Segment.Functions.size());
for (uint64_t FunctionIndex : Segment.Functions)
TableSymbols.push_back(FunctionSymbols[FunctionIndex]);
}
DEBUG(dbgs() << "TableSymbols: " << TableSymbols.size() << "\n");
DEBUG(dbgs() << "Functions : " << FunctionSymbols.size() << "\n"); DEBUG(dbgs() << "Functions : " << FunctionSymbols.size() << "\n");
DEBUG(dbgs() << "Globals : " << GlobalSymbols.size() << "\n"); DEBUG(dbgs() << "Globals : " << GlobalSymbols.size() << "\n");
} }

View File

@ -94,8 +94,8 @@ public:
void dumpInfo() const; void dumpInfo() const;
uint32_t relocateFunctionIndex(uint32_t Original) const; uint32_t relocateFunctionIndex(uint32_t Original) const;
uint32_t getRelocatedAddress(uint32_t Index) const;
uint32_t calcNewIndex(const WasmRelocation &Reloc) const; uint32_t calcNewIndex(const WasmRelocation &Reloc) const;
uint32_t calcNewValue(const WasmRelocation &Reloc) const;
const WasmSection *CodeSection = nullptr; const WasmSection *CodeSection = nullptr;
const WasmSection *DataSection = nullptr; const WasmSection *DataSection = nullptr;
@ -104,10 +104,14 @@ public:
std::vector<InputSegment *> Segments; std::vector<InputSegment *> Segments;
std::vector<InputFunction *> Functions; std::vector<InputFunction *> Functions;
ArrayRef<Symbol *> getSymbols() { return Symbols; } ArrayRef<Symbol *> getSymbols() const { return Symbols; }
ArrayRef<Symbol *> getTableSymbols() { return TableSymbols; }
Symbol *getFunctionSymbol(uint32_t Index) const {
return FunctionSymbols[Index];
}
private: private:
uint32_t relocateVirtualAddress(uint32_t Index) const;
uint32_t relocateTypeIndex(uint32_t Original) const; uint32_t relocateTypeIndex(uint32_t Original) const;
uint32_t relocateGlobalIndex(uint32_t Original) const; uint32_t relocateGlobalIndex(uint32_t Original) const;
uint32_t relocateTableIndex(uint32_t Original) const; uint32_t relocateTableIndex(uint32_t Original) const;
@ -134,9 +138,6 @@ private:
// List of all global symbols indexed by the global index space // List of all global symbols indexed by the global index space
std::vector<Symbol *> GlobalSymbols; std::vector<Symbol *> GlobalSymbols;
// List of all indirect symbols indexed by table index space.
std::vector<Symbol *> TableSymbols;
uint32_t NumGlobalImports = 0; uint32_t NumGlobalImports = 0;
uint32_t NumFunctionImports = 0; uint32_t NumFunctionImports = 0;
std::unique_ptr<WasmObjectFile> WasmObj; std::unique_ptr<WasmObjectFile> WasmObj;

View File

@ -744,12 +744,26 @@ void Writer::assignIndexes() {
for (ObjFile *File : Symtab->ObjectFiles) { for (ObjFile *File : Symtab->ObjectFiles) {
DEBUG(dbgs() << "Table Indexes: " << File->getName() << "\n"); DEBUG(dbgs() << "Table Indexes: " << File->getName() << "\n");
for (Symbol *Sym : File->getTableSymbols()) { auto HandleTableRelocs = [&](InputChunk *Chunk) {
if (!Sym || Sym->hasTableIndex() || !Sym->hasOutputIndex()) if (Chunk->Discarded)
continue; return;
Sym->setTableIndex(TableIndex++); for (const WasmRelocation& Reloc : Chunk->getRelocations()) {
IndirectFunctions.emplace_back(Sym); if (Reloc.Type != R_WEBASSEMBLY_TABLE_INDEX_I32 &&
} Reloc.Type != R_WEBASSEMBLY_TABLE_INDEX_SLEB)
continue;
DEBUG(dbgs() << "getFunctionSymbol: " << Reloc.Index << "\n");
Symbol *Sym = File->getFunctionSymbol(Reloc.Index);
DEBUG(dbgs() << "gotFunctionSymbol: " << Sym->getName() << "\n");
if (Sym->hasTableIndex() || !Sym->hasOutputIndex())
continue;
Sym->setTableIndex(TableIndex++);
IndirectFunctions.emplace_back(Sym);
}
};
for (InputFunction* Function : File->Functions)
HandleTableRelocs(Function);
for (InputSegment* Segment : File->Segments)
HandleTableRelocs(Segment);
} }
} }