-@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
declare i32 @foo() local_unnamed_addr
-define i32 @bar() {
+define i64 @bar() {
entry:
- ret i32 1
+ ret i64 1
}
define void @call_bar_indirect() local_unnamed_addr #1 {
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
- %call = tail call i32 %0() #2
+ %call0 = tail call i64 %0() #2
+ %call1 = tail call i32 %1() #2
ret void
}
; CHECK-NEXT: - Type: TYPE
; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0
-; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ReturnType: I64
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 3
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I32
-; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: - Index: 4
; CHECK-NEXT: ReturnType: I64
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I64
; 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: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
; CHECK-NEXT: Functions:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 41010B
+; CHECK-NEXT: Body: 42010B
; CHECK-NEXT: - Index: 1
-; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 410028028088808000118080808000001A0B
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: - Type: I32
+; CHECK-NEXT: Count: 1
+; CHECK-NEXT: Body: 4100280284888080002100410028028088808000118080808000001A2000118280808000001A0B
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41020B
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 410028028888808000118080808000001A41000B
+; CHECK-NEXT: Body: 410028028888808000118280808000001A41000B
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 42012000118380808000001A0B
+; CHECK-NEXT: Body: 42012000118480808000001A0B
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B
; RELOC-NEXT: Index: 5
; RELOC-NEXT: Offset: 0x0000006A
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
-; RELOC-NEXT: Index: 3
+; RELOC-NEXT: Index: 9
; RELOC-NEXT: Offset: 0x00000073
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
-; RELOC-NEXT: Index: 4
+; RELOC-NEXT: Index: 10
; RELOC-NEXT: Offset: 0x0000007C
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
-; RELOC-NEXT: Index: 5
+; RELOC-NEXT: Index: 11
; RELOC-NEXT: Offset: 0x00000085
; RELOC-NEXT: Functions:
; RELOC-NEXT: - Index: 0
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 4
; CHECK-NEXT: Offset: 0x00000012
; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
; CHECK-NEXT: Index: 1
switch (Reloc.Reloc.Type) {
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+ case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
ExistingValue = decodeULEB128(Buf);
+ // Additional check to verify that the existing value that the location
+ // matches our expectations.
if (ExistingValue != Reloc.Reloc.Index) {
DEBUG(dbgs() << "existing value: " << decodeULEB128(Buf) << "\n");
assert(decodeULEB128(Buf) == Reloc.Reloc.Index);
}
LLVM_FALLTHROUGH;
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
- case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
encodeULEB128(Reloc.Value, Buf, 5);
break;
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:
encodeSLEB128(static_cast<int32_t>(Reloc.Value), Buf, 5);
break;
if (Config->Relocatable)
NewReloc.NewIndex = File->calcNewIndex(Reloc);
- 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) + Reloc.Addend;
- break;
- default:
- NewReloc.Value = File->calcNewIndex(Reloc);
- break;
- }
-
+ NewReloc.Value = File->calcNewValue(Reloc);
OutRelocations.emplace_back(NewReloc);
}
}
}
uint32_t getOutputOffset() const { return OutputOffset; }
+ ArrayRef<WasmRelocation> getRelocations() const { return Relocations; }
virtual StringRef getComdat() const = 0;
" Total Functions : " + Twine(FunctionSymbols.size()) + "\n" +
" Total Globals : " + Twine(GlobalSymbols.size()) + "\n" +
" Function Imports : " + Twine(NumFunctionImports) + "\n" +
- " Global Imports : " + Twine(NumGlobalImports) + "\n" +
- " Table Entries : " + Twine(TableSymbols.size()) + "\n");
+ " Global Imports : " + Twine(NumGlobalImports) + "\n");
}
-uint32_t ObjFile::getRelocatedAddress(uint32_t GlobalIndex) const {
+uint32_t ObjFile::relocateVirtualAddress(uint32_t GlobalIndex) const {
return GlobalSymbols[GlobalIndex]->getVirtualAddress();
}
}
uint32_t ObjFile::relocateTableIndex(uint32_t Original) const {
- Symbol *Sym = TableSymbols[Original];
+ Symbol *Sym = FunctionSymbols[Original];
uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0;
DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original
<< " -> " << Index << "\n");
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
return relocateTypeIndex(Reloc.Index);
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
- return relocateFunctionIndex(Reloc.Index);
case R_WEBASSEMBLY_TABLE_INDEX_I32:
case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
- return relocateTableIndex(Reloc.Index);
+ return relocateFunctionIndex(Reloc.Index);
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
}
}
+// 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() {
// Parse a memory buffer as a wasm file.
DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n");
for (size_t I = 0; I < GlobalSymbols.size(); ++I)
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() << "Globals : " << GlobalSymbols.size() << "\n");
}
void dumpInfo() const;
uint32_t relocateFunctionIndex(uint32_t Original) const;
- uint32_t getRelocatedAddress(uint32_t Index) const;
uint32_t calcNewIndex(const WasmRelocation &Reloc) const;
+ uint32_t calcNewValue(const WasmRelocation &Reloc) const;
const WasmSection *CodeSection = nullptr;
const WasmSection *DataSection = nullptr;
std::vector<InputSegment *> Segments;
std::vector<InputFunction *> Functions;
- ArrayRef<Symbol *> getSymbols() { return Symbols; }
- ArrayRef<Symbol *> getTableSymbols() { return TableSymbols; }
+ ArrayRef<Symbol *> getSymbols() const { return Symbols; }
+
+ Symbol *getFunctionSymbol(uint32_t Index) const {
+ return FunctionSymbols[Index];
+ }
private:
+ uint32_t relocateVirtualAddress(uint32_t Index) const;
uint32_t relocateTypeIndex(uint32_t Original) const;
uint32_t relocateGlobalIndex(uint32_t Original) const;
uint32_t relocateTableIndex(uint32_t Original) const;
// List of all global symbols indexed by the global index space
std::vector<Symbol *> GlobalSymbols;
- // List of all indirect symbols indexed by table index space.
- std::vector<Symbol *> TableSymbols;
-
uint32_t NumGlobalImports = 0;
uint32_t NumFunctionImports = 0;
std::unique_ptr<WasmObjectFile> WasmObj;
for (ObjFile *File : Symtab->ObjectFiles) {
DEBUG(dbgs() << "Table Indexes: " << File->getName() << "\n");
- for (Symbol *Sym : File->getTableSymbols()) {
- if (!Sym || Sym->hasTableIndex() || !Sym->hasOutputIndex())
- continue;
- Sym->setTableIndex(TableIndex++);
- IndirectFunctions.emplace_back(Sym);
- }
+ auto HandleTableRelocs = [&](InputChunk *Chunk) {
+ if (Chunk->Discarded)
+ return;
+ for (const WasmRelocation& Reloc : Chunk->getRelocations()) {
+ 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);
}
}