Index: include/llvm/BinaryFormat/Wasm.h =================================================================== --- include/llvm/BinaryFormat/Wasm.h +++ include/llvm/BinaryFormat/Wasm.h @@ -176,6 +176,11 @@ // Linking metadata kinds. enum : unsigned { WASM_STACK_POINTER = 0x1, + WASM_SYMBOL_INFO = 0x2, +}; + +enum : unsigned { + WASM_SYMBOL_FLAG_WEAK = 0x1, }; #define WASM_RELOC(name, value) name = value, Index: include/llvm/MC/MCSymbolWasm.h =================================================================== --- include/llvm/MC/MCSymbolWasm.h +++ include/llvm/MC/MCSymbolWasm.h @@ -17,6 +17,7 @@ class MCSymbolWasm : public MCSymbol { private: bool IsFunction = false; + bool IsWeak = false; std::string ModuleName; SmallVector Returns; SmallVector Params; @@ -39,6 +40,9 @@ bool isFunction() const { return IsFunction; } void setIsFunction(bool isFunc) { IsFunction = isFunc; } + bool isWeak() const { return IsWeak; } + void setWeak(bool isWeak) { IsWeak = isWeak; } + const StringRef getModuleName() const { return ModuleName; } const SmallVector &getReturns() const { return Returns; } Index: include/llvm/Object/Wasm.h =================================================================== --- include/llvm/Object/Wasm.h +++ include/llvm/Object/Wasm.h @@ -19,6 +19,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringMap.h" #include "llvm/BinaryFormat/Wasm.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" @@ -48,7 +49,24 @@ StringRef Name; SymbolType Type; uint32_t Section; + uint32_t Flags = 0; + + // Index into the imports, exports or functions array of the object depending + // on the type uint32_t ElementIndex; + + bool isWeak() const { + return Flags & wasm::WASM_SYMBOL_FLAG_WEAK; + } + + void print(raw_ostream &Out) const { + Out << "Name=" << Name << ", Type=" << static_cast(Type) + << ", Flags=" << Flags; + } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const { print(dbgs()); } +#endif }; class WasmSection { @@ -63,6 +81,7 @@ }; class WasmObjectFile : public ObjectFile { + public: WasmObjectFile(MemoryBufferRef Object, Error &Err); @@ -176,6 +195,7 @@ // Custom section types Error parseNameSection(const uint8_t *Ptr, const uint8_t *End); + Error parseLinkingSection(const uint8_t *Ptr, const uint8_t *End); Error parseRelocSection(StringRef Name, const uint8_t *Ptr, const uint8_t *End); @@ -190,13 +210,22 @@ std::vector Exports; std::vector ElemSegments; std::vector DataSegments; - std::vector Symbols; std::vector Functions; + std::vector Symbols; ArrayRef CodeSection; uint32_t StartFunction = -1; + + StringMap SymbolMap; }; } // end namespace object + +inline raw_ostream &operator<<(raw_ostream &OS, + const object::WasmSymbol &Sym) { + Sym.print(OS); + return OS; +} + } // end namespace llvm #endif // LLVM_OBJECT_WASM_H Index: include/llvm/ObjectYAML/WasmYAML.h =================================================================== --- include/llvm/ObjectYAML/WasmYAML.h +++ include/llvm/ObjectYAML/WasmYAML.h @@ -112,6 +112,11 @@ ValueType ReturnType; }; +struct SymbolInfo { + StringRef Name; + uint32_t Flags; +}; + struct Section { Section(SectionType SecType) : Type(SecType) {} virtual ~Section(); @@ -121,20 +126,35 @@ }; struct CustomSection : Section { - CustomSection() : Section(wasm::WASM_SEC_CUSTOM) {} + CustomSection(StringRef Name) : Section(wasm::WASM_SEC_CUSTOM), Name(Name) {} static bool classof(const Section *S) { return S->Type == wasm::WASM_SEC_CUSTOM; } StringRef Name; yaml::BinaryRef Payload; +}; + +struct NameSection : CustomSection { + NameSection() : CustomSection("name") {} + static bool classof(const Section *S) { + auto C = dyn_cast(S); + return C && C->Name == "name"; + } - // The follow is used by the "name" custom section. - // TODO(sbc): Add support for more then just functions names. The wasm - // name section can support multiple sub-sections. std::vector FunctionNames; }; +struct LinkingSection : CustomSection { + LinkingSection() : CustomSection("linking") {} + static bool classof(const Section *S) { + auto C = dyn_cast(S); + return C && C->Name == "linking"; + } + + std::vector SymbolInfos; +}; + struct TypeSection : Section { TypeSection() : Section(wasm::WASM_SEC_TYPE) {} static bool classof(const Section *S) { @@ -256,6 +276,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::LocalDecl) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Relocation) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::NameEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SymbolInfo) LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t) namespace llvm { @@ -329,6 +350,10 @@ static void mapping(IO &IO, WasmYAML::ElemSegment &Segment); }; +template <> struct MappingTraits { + static void mapping(IO &IO, WasmYAML::SymbolInfo &Info); +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, WasmYAML::ValueType &Type); }; Index: lib/MC/MCWasmStreamer.cpp =================================================================== --- lib/MC/MCWasmStreamer.cpp +++ lib/MC/MCWasmStreamer.cpp @@ -98,18 +98,30 @@ case MCSA_WeakDefAutoPrivate: case MCSA_Invalid: case MCSA_IndirectSymbol: + case MCSA_Hidden: return false; + + case MCSA_Weak: + case MCSA_WeakReference: + Symbol->setWeak(true); + Symbol->setExternal(true); + break; + case MCSA_Global: Symbol->setExternal(true); break; + case MCSA_ELF_TypeFunction: Symbol->setIsFunction(true); break; + case MCSA_ELF_TypeObject: Symbol->setIsFunction(false); break; + default: // unrecognized directive + llvm_unreachable("unexpected MCSymbolAttr"); return false; } Index: lib/MC/WasmObjectWriter.cpp =================================================================== --- lib/MC/WasmObjectWriter.cpp +++ lib/MC/WasmObjectWriter.cpp @@ -156,9 +156,18 @@ Out << "Off=" << Offset << ", Sym=" << Symbol << ", Addend=" << Addend << ", Type=" << Type << ", FixupSection=" << FixupSection; } - void dump() const { print(errs()); } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const { print(dbgs()); } +#endif }; +inline raw_ostream &operator<<(raw_ostream &OS, + const WasmRelocationEntry &Rel) { + Rel.print(OS); + return OS; +} + class WasmObjectWriter : public MCObjectWriter { /// Helper struct for containing some precomputed information on symbols. struct WasmSymbolData { @@ -229,6 +238,11 @@ void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; + void writeString(const StringRef Str) { + encodeULEB128(Str.size(), getStream()); + writeBytes(Str); + } + void writeValueType(wasm::ValType Ty) { encodeSLEB128(int32_t(Ty), getStream()); } @@ -250,7 +264,8 @@ uint32_t NumFuncImports); void writeCodeRelocSection(); void writeDataRelocSection(uint64_t DataSectionHeaderSize); - void writeLinkingMetaDataSection(bool HasStackPointer, + void writeLinkingMetaDataSection(ArrayRef WeakSymbols, + bool HasStackPointer, uint32_t StackPointerGlobal); void applyRelocations(ArrayRef Relocations, @@ -282,6 +297,7 @@ assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) && "Only custom sections can have names"); + DEBUG(dbgs() << "startSection " << SectionId << ": " << Name << "\n"); encodeULEB128(SectionId, getStream()); Section.SizeOffset = getStream().tell(); @@ -295,8 +311,8 @@ // Custom sections in wasm also have a string identifier. if (SectionId == wasm::WASM_SEC_CUSTOM) { - encodeULEB128(strlen(Name), getStream()); - writeBytes(Name); + assert(Name); + writeString(StringRef(Name)); } } @@ -307,6 +323,7 @@ if (uint32_t(Size) != Size) report_fatal_error("section size does not fit in a uint32_t"); + DEBUG(dbgs() << "endSection size=" << Size << "\n"); unsigned Padding = PaddingFor5ByteULEB128(Size); // Write the final section size to the payload_len field, which follows @@ -411,6 +428,7 @@ unsigned Type = getRelocType(Target, Fixup); WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); + DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); if (FixupSection.hasInstructions()) CodeRelocations.push_back(Rec); @@ -455,7 +473,7 @@ const MCSymbolWasm *Sym = RelEntry.Symbol; // For undefined symbols, use a hopefully invalid value. - if (!Sym->isDefined(false)) + if (!Sym->isDefined(/*SetUsed=*/false)) return UINT32_MAX; MCSectionWasm &Section = @@ -473,17 +491,23 @@ switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: - assert(IndirectSymbolIndices.count(RelEntry.Symbol)); + if (!IndirectSymbolIndices.count(RelEntry.Symbol)) + report_fatal_error("symbol not found table index space:" + + RelEntry.Symbol->getName()); return IndirectSymbolIndices[RelEntry.Symbol]; case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: - assert(SymbolIndices.count(RelEntry.Symbol)); + if (!SymbolIndices.count(RelEntry.Symbol)) + report_fatal_error("symbol not found function/global index space:" + + RelEntry.Symbol->getName()); return SymbolIndices[RelEntry.Symbol]; case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: - assert(TypeIndices.count(RelEntry.Symbol)); + if (!TypeIndices.count(RelEntry.Symbol)) + report_fatal_error("symbol not found in type index space:" + + RelEntry.Symbol->getName()); return TypeIndices[RelEntry.Symbol]; default: llvm_unreachable("invalid relocation type"); @@ -500,6 +524,7 @@ RelEntry.FixupSection->getSectionOffset() + RelEntry.Offset; + DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n"); switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: @@ -577,6 +602,7 @@ endSection(Section); } + void WasmObjectWriter::writeImportSection( const SmallVector &Imports) { if (Imports.empty()) @@ -587,13 +613,8 @@ encodeULEB128(Imports.size(), getStream()); for (const WasmImport &Import : Imports) { - StringRef ModuleName = Import.ModuleName; - encodeULEB128(ModuleName.size(), getStream()); - writeBytes(ModuleName); - - StringRef FieldName = Import.FieldName; - encodeULEB128(FieldName.size(), getStream()); - writeBytes(FieldName); + writeString(Import.ModuleName); + writeString(Import.FieldName); encodeULEB128(Import.Kind, getStream()); @@ -701,11 +722,8 @@ encodeULEB128(Exports.size(), getStream()); for (const WasmExport &Export : Exports) { - encodeULEB128(Export.FieldName.size(), getStream()); - writeBytes(Export.FieldName); - + writeString(Export.FieldName); encodeSLEB128(Export.Kind, getStream()); - encodeULEB128(Export.Index, getStream()); } @@ -750,15 +768,6 @@ MCSectionWasm &FuncSection = static_cast(Func.Sym->getSection()); - if (Func.Sym->isVariable()) - report_fatal_error("weak symbols not supported yet"); - - if (Func.Sym->getOffset() != 0) - report_fatal_error("function sections must contain one function each"); - - if (!Func.Sym->getSize()) - report_fatal_error("function symbols must have a size set with .size"); - int64_t Size = 0; if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout)) report_fatal_error(".size expression must be evaluatable"); @@ -819,15 +828,13 @@ for (const WasmImport &Import : Imports) { if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) { encodeULEB128(Index, getStream()); - encodeULEB128(Import.FieldName.size(), getStream()); - writeBytes(Import.FieldName); + writeString(Import.FieldName); ++Index; } } for (const WasmFunction &Func : Functions) { encodeULEB128(Index, getStream()); - encodeULEB128(Func.Sym->getName().size(), getStream()); - writeBytes(Func.Sym->getName()); + writeString(Func.Sym->getName()); ++Index; } @@ -872,22 +879,37 @@ } void WasmObjectWriter::writeLinkingMetaDataSection( - bool HasStackPointer, uint32_t StackPointerGlobal) { - if (!HasStackPointer) + ArrayRef WeakSymbols, bool HasStackPointer, + uint32_t StackPointerGlobal) { + if (!HasStackPointer && WeakSymbols.empty()) return; + SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); + SectionBookkeeping SubSection; - encodeULEB128(1, getStream()); // count + if (HasStackPointer) { + startSection(SubSection, wasm::WASM_STACK_POINTER); + encodeULEB128(StackPointerGlobal, getStream()); // id + endSection(SubSection); + } - encodeULEB128(wasm::WASM_STACK_POINTER, getStream()); // type - encodeULEB128(StackPointerGlobal, getStream()); // id + if (WeakSymbols.size() != 0) { + startSection(SubSection, wasm::WASM_SYMBOL_INFO); + encodeULEB128(WeakSymbols.size(), getStream()); + for (const StringRef Export: WeakSymbols) { + writeString(Export); + encodeULEB128(wasm::WASM_SYMBOL_FLAG_WEAK, getStream()); + } + endSection(SubSection); + } endSection(Section); } void WasmObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { + DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); MCContext &Ctx = Asm.getContext(); wasm::ValType PtrType = is64Bit() ? wasm::ValType::I64 : wasm::ValType::I32; @@ -898,6 +920,7 @@ SmallVector Globals; SmallVector Imports; SmallVector Exports; + SmallVector WeakSymbols; SmallPtrSet IsAddressTaken; unsigned NumFuncImports = 0; unsigned NumGlobalImports = 0; @@ -906,7 +929,7 @@ bool HasStackPointer = false; // Populate the IsAddressTaken set. - for (WasmRelocationEntry RelEntry : CodeRelocations) { + for (const WasmRelocationEntry &RelEntry : CodeRelocations) { switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: @@ -916,7 +939,7 @@ break; } } - for (WasmRelocationEntry RelEntry : DataRelocations) { + for (const WasmRelocationEntry &RelEntry : DataRelocations) { switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: @@ -1045,14 +1068,32 @@ StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data(); } - // Handle defined symbols. + // Handle regular defined and undefined symbols. for (const MCSymbol &S : Asm.symbols()) { // Ignore unnamed temporary symbols, which aren't ever exported, imported, // or used in relocations. if (S.isTemporary() && S.getName().empty()) continue; + + // Variable references (weak references) are handled in a second pass + if (S.isVariable()) + continue; + const auto &WS = static_cast(S); + DEBUG(dbgs() << "MCSymbol: '" << S << "'" + << " isDefined=" << S.isDefined() << " isExternal=" + << S.isExternal() << " isTemporary=" << S.isTemporary() + << " isFunction=" << WS.isFunction() + << " isWeak=" << WS.isWeak() + << " isVariable=" << WS.isVariable() << "\n"); + + if (WS.isWeak()) + WeakSymbols.push_back(WS.getName()); + unsigned Index; + + //<< " function=" << S.isFunction() + if (WS.isFunction()) { // Prepare the function's type, if we haven't seen it yet. WasmFunctionType F; @@ -1066,6 +1107,14 @@ int32_t Type = Pair.first->second; if (WS.isDefined(/*SetUsed=*/false)) { + if (WS.getOffset() != 0) + report_fatal_error( + "function sections must contain one function each"); + + if (WS.getSize() == 0) + report_fatal_error( + "function symbols must have a size set with .size"); + // A definition. Take the next available index. Index = NumFuncImports + Functions.size(); @@ -1076,6 +1125,9 @@ SymbolIndices[&WS] = Index; Functions.push_back(Func); } else { + // Should be no such thing as weak undefined symbol + assert(!WS.isVariable()); + // An import; the index was assigned above. Index = SymbolIndices.find(&WS)->second; } @@ -1089,7 +1141,7 @@ if (WS.isTemporary() && !WS.getSize()) continue; - if (WS.isDefined(false)) { + if (WS.isDefined(/*SetUsed=*/false)) { if (WS.getOffset() != 0) report_fatal_error("data sections must contain one variable each: " + WS.getName()); @@ -1154,21 +1206,46 @@ } // If the symbol is visible outside this translation unit, export it. - if (WS.isExternal()) { - assert(WS.isDefined(false)); + if (WS.isExternal() && WS.isDefined(/*SetUsed=*/false)) { WasmExport Export; Export.FieldName = WS.getName(); Export.Index = Index; - if (WS.isFunction()) Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; else Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; - Exports.push_back(Export); } } + // Handle weak aliases + for (const MCSymbol &S : Asm.symbols()) { + if (!S.isVariable()) + continue; + assert(S.isExternal()); + assert(S.isDefined(/*SetUsed=*/false)); + + const auto &WS = static_cast(S); + + // Find the target symbol of this weak alias + const MCExpr *Expr = WS.getVariableValue(); + auto *Inner = dyn_cast(Expr); + const MCSymbolWasm *ResolvedSym = cast(&Inner->getSymbol()); + uint32_t Index = SymbolIndices.find(ResolvedSym)->second; + DEBUG(dbgs() << "Weak alias: '" << WS << "' -> '" << ResolvedSym << "' = " << Index << "\n"); + SymbolIndices[&WS] = Index; + + WasmExport Export; + Export.FieldName = WS.getName(); + Export.Index = Index; + if (WS.isFunction()) + Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; + else + Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; + WeakSymbols.push_back(Export.FieldName); + Exports.push_back(Export); + } + // Add types for indirect function calls. for (const WasmRelocationEntry &Fixup : CodeRelocations) { if (Fixup.Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) @@ -1202,7 +1279,7 @@ writeNameSection(Functions, Imports, NumFuncImports); writeCodeRelocSection(); writeDataRelocSection(DataSectionHeaderSize); - writeLinkingMetaDataSection(HasStackPointer, StackPointerGlobal); + writeLinkingMetaDataSection(WeakSymbols, HasStackPointer, StackPointerGlobal); // TODO: Translate the .comment section to the output. // TODO: Translate debug sections to the output. Index: lib/Object/WasmObjectFile.cpp =================================================================== --- lib/Object/WasmObjectFile.cpp +++ lib/Object/WasmObjectFile.cpp @@ -28,6 +28,8 @@ #include #include +#define DEBUG_TYPE "wasm-object" + using namespace llvm; using namespace object; @@ -256,6 +258,7 @@ while (Ptr < End) { uint8_t Type = readVarint7(Ptr); uint32_t Size = readVaruint32(Ptr); + const uint8_t *SubSectionEnd = Ptr + Size; switch (Type) { case wasm::WASM_NAMES_FUNCTION: { uint32_t Count = readVaruint32(Ptr); @@ -275,6 +278,9 @@ Ptr += Size; break; } + if (Ptr != SubSectionEnd) + return make_error("Name sub-section ended prematurely", + object_error::parse_failed); } if (Ptr != End) @@ -283,6 +289,50 @@ return Error::success(); } +Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, + const uint8_t *End) { + while (Ptr < End) { + uint8_t Type = readVarint7(Ptr); + uint32_t Size = readVaruint32(Ptr); + const uint8_t *SubSectionEnd = Ptr + Size; + switch (Type) { + case wasm::WASM_SYMBOL_INFO: { + uint32_t Count = readVaruint32(Ptr); + while (Count--) { + StringRef Symbol = readString(Ptr); + DEBUG(dbgs() << "reading syminfo: " << Symbol << "\n"); + uint32_t Flags = readVaruint32(Ptr); + auto iter = SymbolMap.find(Symbol); + if (iter == SymbolMap.end()) { + return make_error( + "Invalid symbol name in linking section", + object_error::parse_failed); + } + uint32_t SymIndex = iter->second; + assert(SymIndex < Symbols.size()); + Symbols[SymIndex].Flags = Flags; + DEBUG(dbgs() << "Set symbol flags index:" + << SymIndex << " name:" + << Symbols[SymIndex].Name << " exptected:" + << Symbol << " flags: " << Flags << "\n"); + } + break; + } + case wasm::WASM_STACK_POINTER: + default: + Ptr += Size; + break; + } + if (Ptr != SubSectionEnd) + return make_error( + "Linking sub-section ended prematurely", object_error::parse_failed); + } + if (Ptr != End) + return make_error("Linking section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + WasmSection* WasmObjectFile::findCustomSectionByName(StringRef Name) { for (WasmSection& Section : Sections) { if (Section.Type == wasm::WASM_SEC_CUSTOM && Section.Name == Name) @@ -351,6 +401,9 @@ if (Sec.Name == "name") { if (Error Err = parseNameSection(Ptr, End)) return Err; + } else if (Sec.Name == "linking") { + if (Error Err = parseLinkingSection(Ptr, End)) + return Err; } else if (Sec.Name.startswith("reloc.")) { if (Error Err = parseRelocSection(Sec.Name, Ptr, End)) return Err; @@ -402,14 +455,20 @@ switch (Im.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: Im.SigIndex = readVaruint32(Ptr); + SymbolMap.try_emplace(Im.Field, Symbols.size()); Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::FUNCTION_IMPORT, Sections.size(), i); + DEBUG(dbgs() << "Adding import: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_GLOBAL: Im.Global.Type = readVarint7(Ptr); Im.Global.Mutable = readVaruint1(Ptr); + SymbolMap.try_emplace(Im.Field, Symbols.size()); Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT, Sections.size(), i); + DEBUG(dbgs() << "Adding import: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_MEMORY: Im.Memory = readLimits(Ptr); @@ -498,15 +557,20 @@ Ex.Name = readString(Ptr); Ex.Kind = readUint8(Ptr); Ex.Index = readVaruint32(Ptr); - Exports.push_back(Ex); switch (Ex.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: + SymbolMap.try_emplace(Ex.Name, Symbols.size()); Symbols.emplace_back(Ex.Name, WasmSymbol::SymbolType::FUNCTION_EXPORT, Sections.size(), i); + DEBUG(dbgs() << "Adding export: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_GLOBAL: + SymbolMap.try_emplace(Ex.Name, Symbols.size()); Symbols.emplace_back(Ex.Name, WasmSymbol::SymbolType::GLOBAL_EXPORT, Sections.size(), i); + DEBUG(dbgs() << "Adding export: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_MEMORY: case wasm::WASM_EXTERNAL_TABLE: @@ -515,6 +579,7 @@ return make_error( "Unexpected export kind", object_error::parse_failed); } + Exports.push_back(Ex); } if (Ptr != End) return make_error("Export section ended prematurely", @@ -622,6 +687,10 @@ uint32_t Result = SymbolRef::SF_None; const WasmSymbol &Sym = getWasmSymbol(Symb); + DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n"); + if (Sym.Flags & wasm::WASM_SYMBOL_FLAG_WEAK) + Result |= SymbolRef::SF_Weak; + switch (Sym.Type) { case WasmSymbol::SymbolType::FUNCTION_IMPORT: Result |= SymbolRef::SF_Undefined | SymbolRef::SF_Executable; @@ -631,6 +700,7 @@ break; case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: Result |= SymbolRef::SF_Executable; + Result |= SymbolRef::SF_FormatSpecific; break; case WasmSymbol::SymbolType::GLOBAL_IMPORT: Result |= SymbolRef::SF_Undefined; @@ -664,8 +734,7 @@ } Expected WasmObjectFile::getSymbolName(DataRefImpl Symb) const { - const WasmSymbol &Sym = getWasmSymbol(Symb); - return Sym.Name; + return getWasmSymbol(Symb).Name; } Expected WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { @@ -673,8 +742,17 @@ } uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { - const WasmSymbol &Sym = getWasmSymbol(Symb); - return Sym.ElementIndex; + const WasmSymbol& Sym = getWasmSymbol(Symb); + switch (Sym.Type) { + case WasmSymbol::SymbolType::FUNCTION_IMPORT: + case WasmSymbol::SymbolType::GLOBAL_IMPORT: + return 0; + case WasmSymbol::SymbolType::FUNCTION_EXPORT: + case WasmSymbol::SymbolType::GLOBAL_EXPORT: + return Exports[Sym.ElementIndex].Index; + case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: + return Sym.ElementIndex; + } } uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const { Index: lib/ObjectYAML/WasmYAML.cpp =================================================================== --- lib/ObjectYAML/WasmYAML.cpp +++ lib/ObjectYAML/WasmYAML.cpp @@ -47,14 +47,22 @@ IO.mapOptional("Relocations", Section.Relocations); } +static void sectionMapping(IO &IO, WasmYAML::NameSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("Name", Section.Name); + IO.mapOptional("FunctionNames", Section.FunctionNames); +} + +static void sectionMapping(IO &IO, WasmYAML::LinkingSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("Name", Section.Name); + IO.mapRequired("SymbolInfo", Section.SymbolInfos); +} + static void sectionMapping(IO &IO, WasmYAML::CustomSection &Section) { commonSectionMapping(IO, Section); IO.mapRequired("Name", Section.Name); - if (Section.Name == "name") { - IO.mapOptional("FunctionNames", Section.FunctionNames); - } else { - IO.mapRequired("Payload", Section.Payload); - } + IO.mapRequired("Payload", Section.Payload); } static void sectionMapping(IO &IO, WasmYAML::TypeSection &Section) { @@ -121,11 +129,29 @@ IO.mapRequired("Type", SectionType); switch (SectionType) { - case wasm::WASM_SEC_CUSTOM: - if (!IO.outputting()) - Section.reset(new WasmYAML::CustomSection()); - sectionMapping(IO, *cast(Section.get())); + case wasm::WASM_SEC_CUSTOM: { + StringRef SectionName; + if (IO.outputting()) { + auto CustomSection = cast(Section.get()); + SectionName = CustomSection->Name; + } else { + IO.mapRequired("Name", SectionName); + } + if (SectionName == "linking") { + if (!IO.outputting()) + Section.reset(new WasmYAML::LinkingSection()); + sectionMapping(IO, *cast(Section.get())); + } else if (SectionName == "name") { + if (!IO.outputting()) + Section.reset(new WasmYAML::NameSection()); + sectionMapping(IO, *cast(Section.get())); + } else { + if (!IO.outputting()) + Section.reset(new WasmYAML::CustomSection(SectionName)); + sectionMapping(IO, *cast(Section.get())); + } break; + } case wasm::WASM_SEC_TYPE: if (!IO.outputting()) Section.reset(new WasmYAML::TypeSection()); @@ -321,6 +347,12 @@ IO.mapRequired("Content", Segment.Content); } +void MappingTraits::mapping(IO &IO, + WasmYAML::SymbolInfo &Info) { + IO.mapRequired("Name", Info.Name); + IO.mapRequired("Flags", Info.Flags); +} + void ScalarEnumerationTraits::enumeration( IO &IO, WasmYAML::ValueType &Type) { #define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X); Index: test/ObjectYAML/wasm/weak_symbols.yaml =================================================================== --- /dev/null +++ test/ObjectYAML/wasm/weak_symbols.yaml @@ -0,0 +1,40 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: EXPORT + Exports: + - Name: function_export + Kind: FUNCTION + Index: 1 + - Name: global_export + Kind: GLOBAL + Index: 2 + - Type: CUSTOM + Name: linking + SymbolInfo: + - Name: function_export + Flags: 1 + - Name: global_export + Flags: 1 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: EXPORT +# CHECK: Exports: +# CHECK: - Name: function_export +# CHECK: Kind: FUNCTION +# CHECK: Index: 1 +# CHECK: - Name: global_export +# CHECK: Kind: GLOBAL +# CHECK: Index: 2 +# CHECK: - Type: CUSTOM +# CHECK: Name: linking +# CHECK: SymbolInfo: +# CHECK: - Name: function_export +# CHECK: Flags: 1 +# CHECK: - Name: global_export +# CHECK: Flags: 1 Index: test/tools/llvm-nm/wasm/exports.yaml =================================================================== --- test/tools/llvm-nm/wasm/exports.yaml +++ test/tools/llvm-nm/wasm/exports.yaml @@ -1,5 +1,8 @@ # RUN: yaml2obj < %s | llvm-nm - | FileCheck %s +# That wasm exports of functions and globals are displayed as global data and +# code symbols. + --- !WASM FileHeader: Version: 0x00000001 @@ -13,10 +16,10 @@ Exports: - Name: foo Kind: FUNCTION - Index: 0x00000000 + Index: 0x00000004 - Name: bar Kind: GLOBAL - Index: 0x00000000 + Index: 0x00000002 -# CHECK: 00000001 D bar -# CHECK: 00000000 T foo +# CHECK: 00000002 D bar +# CHECK: 00000004 T foo Index: test/tools/llvm-nm/wasm/weak-symbols.yaml =================================================================== --- /dev/null +++ test/tools/llvm-nm/wasm/weak-symbols.yaml @@ -0,0 +1,49 @@ +# RUN: yaml2obj < %s | llvm-nm - | FileCheck %s + +# That wasm exports of functions and globals are displayed as global data and +# code symbols. + +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - ReturnType: I32 + ParamTypes: + - I32 + - Type: IMPORT + Imports: + - Module: env + Field: weak_import_func + Kind: FUNCTION + SigIndex: 0 + - Module: env + Field: weak_import_data + Kind: GLOBAL + GlobalType: I32 + GlobalMutable: false + - Type: EXPORT + Exports: + - Name: weak_global_func + Kind: FUNCTION + Index: 0x00000004 + - Name: weak_global_data + Kind: GLOBAL + Index: 0x00000002 + - Type: CUSTOM + Name: linking + SymbolInfo: + - Name: weak_global_func + Flags: 1 + - Name: weak_global_data + Flags: 1 + - Name: weak_import_func + Flags: 1 + - Name: weak_import_data + Flags: 1 + +# CHECK: 00000002 W weak_global_data +# CHECK: 00000004 W weak_global_func +# CHECK: w weak_import_data +# CHECK: w weak_import_func Index: tools/obj2yaml/wasm2yaml.cpp =================================================================== --- tools/obj2yaml/wasm2yaml.cpp +++ tools/obj2yaml/wasm2yaml.cpp @@ -14,6 +14,7 @@ #include "llvm/Support/YAMLTraits.h" using namespace llvm; +using object::WasmSection; namespace { @@ -22,10 +23,16 @@ public: WasmDumper(const object::WasmObjectFile &O) : Obj(O) {} + ErrorOr dump(); + + std::unique_ptr + dumpCustomSection(const WasmSection &WasmSec); }; -WasmYAML::Table make_table(const wasm::WasmTable &Table) { +} // namespace + +static WasmYAML::Table make_table(const wasm::WasmTable &Table) { WasmYAML::Table T; T.ElemType = Table.ElemType; T.TableLimits.Flags = Table.Limits.Flags; @@ -34,7 +41,7 @@ return T; } -WasmYAML::Limits make_limits(const wasm::WasmLimits &Limits) { +static WasmYAML::Limits make_limits(const wasm::WasmLimits &Limits) { WasmYAML::Limits L; L.Flags = Limits.Flags; L.Initial = Limits.Initial; @@ -42,6 +49,42 @@ return L; } +std::unique_ptr WasmDumper::dumpCustomSection(const WasmSection &WasmSec) { + std::unique_ptr CustomSec; + if (WasmSec.Name == "name") { + std::unique_ptr NameSec = make_unique(); + for (const object::SymbolRef& Sym: Obj.symbols()) { + uint32_t Flags = Sym.getFlags(); + // Skip over symbols that come from imports or exports + if (Flags & + (object::SymbolRef::SF_Global | object::SymbolRef::SF_Undefined)) + continue; + Expected NameOrError = Sym.getName(); + if (!NameOrError) + continue; + WasmYAML::NameEntry NameEntry; + NameEntry.Name = *NameOrError; + NameEntry.Index = Sym.getValue(); + NameSec->FunctionNames.push_back(NameEntry); + } + CustomSec = std::move(NameSec); + } else if (WasmSec.Name == "linking") { + std::unique_ptr LinkingSec = make_unique(); + for (const object::SymbolRef& Sym: Obj.symbols()) { + const object::WasmSymbol Symbol = Obj.getWasmSymbol(Sym); + if (Symbol.Flags != 0) { + WasmYAML::SymbolInfo Info = { Symbol.Name, Symbol.Flags }; + LinkingSec->SymbolInfos.push_back(Info); + } + } + CustomSec = std::move(LinkingSec); + } else { + CustomSec = make_unique(WasmSec.Name); + } + CustomSec->Payload = yaml::BinaryRef(WasmSec.Content); + return CustomSec; +} + ErrorOr WasmDumper::dump() { auto Y = make_unique(); @@ -50,7 +93,7 @@ // Dump sections for (const auto &Sec : Obj.sections()) { - const object::WasmSection &WasmSec = Obj.getWasmSection(Sec); + const WasmSection &WasmSec = Obj.getWasmSection(Sec); std::unique_ptr S; switch (WasmSec.Type) { case wasm::WASM_SEC_CUSTOM: { @@ -59,27 +102,7 @@ // being represented as a custom section in the YAML output. continue; } - auto CustomSec = make_unique(); - CustomSec->Name = WasmSec.Name; - if (CustomSec->Name == "name") { - for (const object::SymbolRef& Sym: Obj.symbols()) { - uint32_t Flags = Sym.getFlags(); - // Skip over symbols that come from imports or exports - if (Flags & - (object::SymbolRef::SF_Global | object::SymbolRef::SF_Undefined)) - continue; - Expected NameOrError = Sym.getName(); - if (!NameOrError) - continue; - WasmYAML::NameEntry NameEntry; - NameEntry.Name = *NameOrError; - NameEntry.Index = Sym.getValue(); - CustomSec->FunctionNames.push_back(NameEntry); - } - } else { - CustomSec->Payload = yaml::BinaryRef(WasmSec.Content); - } - S = std::move(CustomSec); + S = dumpCustomSection(WasmSec); break; } case wasm::WASM_SEC_TYPE: { @@ -237,8 +260,6 @@ return Y.release(); } -} // namespace - std::error_code wasm2yaml(raw_ostream &Out, const object::WasmObjectFile &Obj) { WasmDumper Dumper(Obj); ErrorOr YAMLOrErr = Dumper.dump(); Index: tools/yaml2obj/yaml2wasm.cpp =================================================================== --- tools/yaml2obj/yaml2wasm.cpp +++ tools/yaml2obj/yaml2wasm.cpp @@ -26,8 +26,9 @@ public: WasmWriter(WasmYAML::Object &Obj) : Obj(Obj) {} int writeWasm(raw_ostream &OS); + +private: int writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec); - int writeNameSection(raw_ostream &OS, WasmYAML::CustomSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::CustomSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::TypeSection &Section); @@ -42,7 +43,9 @@ int writeSectionContent(raw_ostream &OS, WasmYAML::CodeSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::DataSection &Section); -private: + // Custom section types + int writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section); WasmYAML::Object &Obj; }; @@ -107,12 +110,30 @@ return 0; } -int WasmWriter::writeNameSection(raw_ostream &OS, - WasmYAML::CustomSection &Section) { +int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section) { + writeStringRef(Section.Name, OS); + if (Section.SymbolInfos.size()) { + encodeULEB128(wasm::WASM_SYMBOL_INFO, OS); + std::string OutString; + raw_string_ostream StringStream(OutString); + + encodeULEB128(Section.SymbolInfos.size(), StringStream); + for (const WasmYAML::SymbolInfo &Info : Section.SymbolInfos) { + writeStringRef(Info.Name, StringStream); + encodeULEB128(Info.Flags, StringStream); + } + + StringStream.flush(); + encodeULEB128(OutString.size(), OS); + OS << OutString; + } + return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section) { writeStringRef(Section.Name, OS); if (Section.FunctionNames.size()) { encodeULEB128(wasm::WASM_NAMES_FUNCTION, OS); - std::string OutString; raw_string_ostream StringStream(OutString); @@ -131,8 +152,12 @@ int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::CustomSection &Section) { - if (Section.Name == "name") { - writeNameSection(OS, Section); + if (auto S = dyn_cast(&Section)) { + if (auto Err = writeSectionContent(OS, *S)) + return Err; + } else if (auto S = dyn_cast(&Section)) { + if (auto Err = writeSectionContent(OS, *S)) + return Err; } else { Section.Payload.writeAsBinary(OS); }