diff options
| author | Dan Gohman <dan433584@gmail.com> | 2017-03-30 23:58:19 +0000 |
|---|---|---|
| committer | Dan Gohman <dan433584@gmail.com> | 2017-03-30 23:58:19 +0000 |
| commit | 970d02c42dc122a4a550599aa9153965a521660b (patch) | |
| tree | 585011ec096221540d87c3527856b4e5e25a2c43 /llvm/lib/MC | |
| parent | 1074cb5420f6cec1d2ea039d0f343719de7d84aa (diff) | |
| download | bcm5719-llvm-970d02c42dc122a4a550599aa9153965a521660b.tar.gz bcm5719-llvm-970d02c42dc122a4a550599aa9153965a521660b.zip | |
[WebAssembly] Initial linking metadata support
Add support for the new relocations and linking metadata section support in
https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md. In
particular, this allows LLVM to indicate which variable is the stack pointer,
so that it can be linked with other objects.
This also adds support for emitting type relocations for call_indirect
instructions.
Right now, this is mainly tested by using wabt and hexdump to examine the
output on selected testcases. We'll add more tests as the design stablizes
and more of the pieces are in place.
llvm-svn: 299141
Diffstat (limited to 'llvm/lib/MC')
| -rw-r--r-- | llvm/lib/MC/WasmObjectWriter.cpp | 146 |
1 files changed, 123 insertions, 23 deletions
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp index 0b703f4387b..548d99fe4b9 100644 --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -50,16 +50,6 @@ struct SectionBookkeeping { uint64_t ContentsOffset; }; -// This record records information about a call_indirect which needs its -// type index fixed up once we've computed type indices. -struct TypeIndexFixup { - uint64_t Offset; - const MCSymbolWasm *Symbol; - const MCSectionWasm *FixupSection; - TypeIndexFixup(uint64_t O, const MCSymbolWasm *S, MCSectionWasm *F) - : Offset(O), Symbol(S), FixupSection(F) {} -}; - class WasmObjectWriter : public MCObjectWriter { /// Helper struct for containing some precomputed information on symbols. struct WasmSymbolData { @@ -80,7 +70,7 @@ class WasmObjectWriter : public MCObjectWriter { std::vector<WasmRelocationEntry> DataRelocations; // Fixups for call_indirect type indices. - std::vector<TypeIndexFixup> TypeIndexFixups; + std::vector<WasmRelocationEntry> TypeIndexFixups; // Index values to use for fixing up call_indirect type indices. std::vector<uint32_t> TypeIndexFixupTypes; @@ -269,8 +259,11 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, if (RefA) { if (RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX) { - TypeIndexFixups.push_back(TypeIndexFixup(FixupOffset, SymA, - &FixupSection)); + assert(C == 0); + WasmRelocationEntry Rec(FixupOffset, SymA, C, + wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB, + &FixupSection); + TypeIndexFixups.push_back(Rec); return; } } @@ -358,7 +351,9 @@ struct WasmExport { struct WasmGlobal { wasm::ValType Type; bool IsMutable; - uint32_t InitialValue; + bool HasImport; + uint64_t InitialValue; + uint32_t ImportIndex; }; } // end anonymous namespace @@ -507,6 +502,29 @@ static void WriteRelocations( } } +// Write out the the type relocation records that the linker will +// need to handle. +static void WriteTypeRelocations( + ArrayRef<WasmRelocationEntry> TypeIndexFixups, + ArrayRef<uint32_t> TypeIndexFixupTypes, + raw_pwrite_stream &Stream) +{ + for (size_t i = 0, e = TypeIndexFixups.size(); i < e; ++i) { + const WasmRelocationEntry &Fixup = TypeIndexFixups[i]; + uint32_t Type = TypeIndexFixupTypes[i]; + + assert(Fixup.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB); + assert(Fixup.Addend == 0); + + uint64_t Offset = Fixup.Offset + + Fixup.FixupSection->getSectionOffset(); + + encodeULEB128(Fixup.Type, Stream); + encodeULEB128(Offset, Stream); + encodeULEB128(Type, Stream); + } +} + void WasmObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { MCContext &Ctx = Asm.getContext(); @@ -526,6 +544,8 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, unsigned NumFuncImports = 0; unsigned NumGlobalImports = 0; SmallVector<char, 0> DataBytes; + uint32_t StackPointerGlobal = 0; + bool HasStackPointer = false; // Populate the IsAddressTaken set. for (WasmRelocationEntry RelEntry : CodeRelocations) { @@ -605,15 +625,68 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, if (!DataFrag.getFixups().empty()) report_fatal_error("fixups not supported in .global_variables"); const SmallVectorImpl<char> &Contents = DataFrag.getContents(); - for (char p : Contents) { + for (const uint8_t *p = (const uint8_t *)Contents.data(), + *end = (const uint8_t *)Contents.data() + Contents.size(); + p != end; ) { WasmGlobal G; - G.Type = wasm::ValType(p); - G.IsMutable = true; - G.InitialValue = 0; + if (end - p < 3) + report_fatal_error("truncated global variable encoding"); + G.Type = wasm::ValType(int8_t(*p++)); + G.IsMutable = bool(*p++); + G.HasImport = bool(*p++); + if (G.HasImport) { + G.InitialValue = 0; + + WasmImport Import; + Import.ModuleName = (const char *)p; + const uint8_t *nul = (const uint8_t *)memchr(p, '\0', end - p); + if (!nul) + report_fatal_error("global module name must be nul-terminated"); + p = nul + 1; + nul = (const uint8_t *)memchr(p, '\0', end - p); + if (!nul) + report_fatal_error("global base name must be nul-terminated"); + Import.FieldName = (const char *)p; + p = nul + 1; + + Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; + Import.Type = int32_t(G.Type); + + G.ImportIndex = NumGlobalImports; + ++NumGlobalImports; + + Imports.push_back(Import); + } else { + unsigned n; + G.InitialValue = decodeSLEB128(p, &n); + G.ImportIndex = 0; + if (n > end - p) + report_fatal_error("global initial value must be valid SLEB128"); + p += n; + } Globals.push_back(G); } } + // In the special .stack_pointer section, we've encoded the stack pointer + // index. + MCSectionWasm *StackPtr = Ctx.getWasmSection(".stack_pointer", 0, 0); + if (!StackPtr->getFragmentList().empty()) { + if (StackPtr->getFragmentList().size() != 1) + report_fatal_error("only one .stack_pointer fragment supported"); + const MCFragment &Frag = *StackPtr->begin(); + if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) + report_fatal_error("only data supported in .stack_pointer"); + const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag); + if (!DataFrag.getFixups().empty()) + report_fatal_error("fixups not supported in .stack_pointer"); + const SmallVectorImpl<char> &Contents = DataFrag.getContents(); + if (Contents.size() != 4) + report_fatal_error("only one entry supported in .stack_pointer"); + HasStackPointer = true; + StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data(); + } + // Handle defined symbols. for (const MCSymbol &S : Asm.symbols()) { // Ignore unnamed temporary symbols, which aren't ever exported, imported, @@ -712,7 +785,9 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, WasmGlobal Global; Global.Type = PtrType; Global.IsMutable = false; + Global.HasImport = false; Global.InitialValue = DataSection.getSectionOffset(); + Global.ImportIndex = 0; SymbolIndices[&WS] = Index; Globals.push_back(Global); } @@ -736,7 +811,10 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, } // Add types for indirect function calls. - for (const TypeIndexFixup &Fixup : TypeIndexFixups) { + for (const WasmRelocationEntry &Fixup : TypeIndexFixups) { + assert(Fixup.Addend == 0); + assert(Fixup.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB); + WasmFunctionType F; F.Returns = Fixup.Symbol->getReturns(); F.Params = Fixup.Symbol->getParams(); @@ -793,7 +871,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, encodeULEB128(Import.Type, getStream()); break; case wasm::WASM_EXTERNAL_GLOBAL: - encodeSLEB128(Import.Type, getStream()); + encodeSLEB128(int32_t(Import.Type), getStream()); encodeULEB128(0, getStream()); // mutability break; default: @@ -853,8 +931,15 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, writeValueType(Global.Type); write8(Global.IsMutable); - write8(wasm::WASM_OPCODE_I32_CONST); - encodeSLEB128(Global.InitialValue, getStream()); // offset + if (Global.HasImport) { + assert(Global.InitialValue == 0); + write8(wasm::WASM_OPCODE_GET_GLOBAL); + encodeULEB128(Global.ImportIndex, getStream()); + } else { + assert(Global.ImportIndex == 0); + write8(wasm::WASM_OPCODE_I32_CONST); + encodeSLEB128(Global.InitialValue, getStream()); // offset + } write8(wasm::WASM_OPCODE_END); } @@ -944,7 +1029,9 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, uint32_t Type = TypeIndexFixupTypes[i]; unsigned Padding = PaddingFor5ByteULEB128(Type); - const TypeIndexFixup &Fixup = TypeIndexFixups[i]; + const WasmRelocationEntry &Fixup = TypeIndexFixups[i]; + assert(Fixup.Addend == 0); + assert(Fixup.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB); uint64_t Offset = Fixup.Offset + Fixup.FixupSection->getSectionOffset(); @@ -1021,6 +1108,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, encodeULEB128(CodeRelocations.size(), getStream()); WriteRelocations(CodeRelocations, getStream(), SymbolIndices); + WriteTypeRelocations(TypeIndexFixups, TypeIndexFixupTypes, getStream()); endSection(Section); } @@ -1038,6 +1126,18 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, endSection(Section); } + // === Linking Metadata Section ============================================== + if (HasStackPointer) { + startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); + + encodeULEB128(1, getStream()); // count + + encodeULEB128(wasm::WASM_STACK_POINTER, getStream()); // type + encodeULEB128(StackPointerGlobal, getStream()); // id + + endSection(Section); + } + // TODO: Translate the .comment section to the output. // TODO: Translate debug sections to the output. |

