1*44d95122SEugene Zelenko //===- WasmObjectFile.cpp - Wasm object file implementation ---------------===// 22c6f75ddSDerek Schuff // 32c6f75ddSDerek Schuff // The LLVM Compiler Infrastructure 42c6f75ddSDerek Schuff // 52c6f75ddSDerek Schuff // This file is distributed under the University of Illinois Open Source 62c6f75ddSDerek Schuff // License. See LICENSE.TXT for details. 72c6f75ddSDerek Schuff // 82c6f75ddSDerek Schuff //===----------------------------------------------------------------------===// 92c6f75ddSDerek Schuff 10*44d95122SEugene Zelenko #include "llvm/ADT/ArrayRef.h" 11*44d95122SEugene Zelenko #include "llvm/ADT/STLExtras.h" 12*44d95122SEugene Zelenko #include "llvm/ADT/StringRef.h" 13*44d95122SEugene Zelenko #include "llvm/ADT/Triple.h" 14*44d95122SEugene Zelenko #include "llvm/Object/Binary.h" 15*44d95122SEugene Zelenko #include "llvm/Object/Error.h" 16*44d95122SEugene Zelenko #include "llvm/Object/ObjectFile.h" 17*44d95122SEugene Zelenko #include "llvm/Object/SymbolicFile.h" 182c6f75ddSDerek Schuff #include "llvm/Object/Wasm.h" 192c6f75ddSDerek Schuff #include "llvm/Support/Endian.h" 20*44d95122SEugene Zelenko #include "llvm/Support/Error.h" 21*44d95122SEugene Zelenko #include "llvm/Support/ErrorHandling.h" 222c6f75ddSDerek Schuff #include "llvm/Support/LEB128.h" 23*44d95122SEugene Zelenko #include "llvm/Support/Wasm.h" 24*44d95122SEugene Zelenko #include <algorithm> 25*44d95122SEugene Zelenko #include <cstdint> 26*44d95122SEugene Zelenko #include <system_error> 272c6f75ddSDerek Schuff 28*44d95122SEugene Zelenko using namespace llvm; 29*44d95122SEugene Zelenko using namespace object; 302c6f75ddSDerek Schuff 312c6f75ddSDerek Schuff Expected<std::unique_ptr<WasmObjectFile>> 322c6f75ddSDerek Schuff ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) { 332c6f75ddSDerek Schuff Error Err = Error::success(); 342c6f75ddSDerek Schuff auto ObjectFile = llvm::make_unique<WasmObjectFile>(Buffer, Err); 352c6f75ddSDerek Schuff if (Err) 362c6f75ddSDerek Schuff return std::move(Err); 372c6f75ddSDerek Schuff 382c6f75ddSDerek Schuff return std::move(ObjectFile); 392c6f75ddSDerek Schuff } 402c6f75ddSDerek Schuff 41*44d95122SEugene Zelenko static uint32_t readUint32(const uint8_t *&Ptr) { 422c6f75ddSDerek Schuff uint32_t Result = support::endian::read32le(Ptr); 432c6f75ddSDerek Schuff Ptr += sizeof(Result); 442c6f75ddSDerek Schuff return Result; 452c6f75ddSDerek Schuff } 462c6f75ddSDerek Schuff 47*44d95122SEugene Zelenko static uint64_t readULEB128(const uint8_t *&Ptr) { 482c6f75ddSDerek Schuff unsigned Count; 492c6f75ddSDerek Schuff uint64_t Result = decodeULEB128(Ptr, &Count); 502c6f75ddSDerek Schuff Ptr += Count; 512c6f75ddSDerek Schuff return Result; 522c6f75ddSDerek Schuff } 532c6f75ddSDerek Schuff 54*44d95122SEugene Zelenko static StringRef readString(const uint8_t *&Ptr) { 552c6f75ddSDerek Schuff uint32_t StringLen = readULEB128(Ptr); 562c6f75ddSDerek Schuff StringRef Return = StringRef(reinterpret_cast<const char *>(Ptr), StringLen); 572c6f75ddSDerek Schuff Ptr += StringLen; 582c6f75ddSDerek Schuff return Return; 592c6f75ddSDerek Schuff } 602c6f75ddSDerek Schuff 61*44d95122SEugene Zelenko static Error readSection(wasm::WasmSection &Section, const uint8_t *&Ptr, 622c6f75ddSDerek Schuff const uint8_t *Start) { 632c6f75ddSDerek Schuff // TODO(sbc): Avoid reading past EOF in the case of malformed files. 642c6f75ddSDerek Schuff Section.Offset = Ptr - Start; 652c6f75ddSDerek Schuff Section.Type = readULEB128(Ptr); 662c6f75ddSDerek Schuff uint32_t Size = readULEB128(Ptr); 672c6f75ddSDerek Schuff if (Size == 0) 682c6f75ddSDerek Schuff return make_error<StringError>("Zero length section", 692c6f75ddSDerek Schuff object_error::parse_failed); 702c6f75ddSDerek Schuff Section.Content = ArrayRef<uint8_t>(Ptr, Size); 712c6f75ddSDerek Schuff Ptr += Size; 722c6f75ddSDerek Schuff return Error::success(); 732c6f75ddSDerek Schuff } 742c6f75ddSDerek Schuff 752c6f75ddSDerek Schuff WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) 762c6f75ddSDerek Schuff : ObjectFile(Binary::ID_Wasm, Buffer) { 772c6f75ddSDerek Schuff ErrorAsOutParameter ErrAsOutParam(&Err); 782c6f75ddSDerek Schuff Header.Magic = getData().substr(0, 4); 792c6f75ddSDerek Schuff if (Header.Magic != StringRef("\0asm", 4)) { 802c6f75ddSDerek Schuff Err = make_error<StringError>("Bad magic number", 812c6f75ddSDerek Schuff object_error::parse_failed); 822c6f75ddSDerek Schuff return; 832c6f75ddSDerek Schuff } 842c6f75ddSDerek Schuff const uint8_t *Ptr = getPtr(4); 852c6f75ddSDerek Schuff Header.Version = readUint32(Ptr); 862c6f75ddSDerek Schuff if (Header.Version != wasm::WasmVersion) { 872c6f75ddSDerek Schuff Err = make_error<StringError>("Bad version number", 882c6f75ddSDerek Schuff object_error::parse_failed); 892c6f75ddSDerek Schuff return; 902c6f75ddSDerek Schuff } 912c6f75ddSDerek Schuff 922c6f75ddSDerek Schuff const uint8_t *Eof = getPtr(getData().size()); 932c6f75ddSDerek Schuff wasm::WasmSection Sec; 942c6f75ddSDerek Schuff while (Ptr < Eof) { 952c6f75ddSDerek Schuff if ((Err = readSection(Sec, Ptr, getPtr(0)))) 962c6f75ddSDerek Schuff return; 976d76b7b4SDerek Schuff if (Sec.Type == wasm::WASM_SEC_CUSTOM) { 986d76b7b4SDerek Schuff if ((Err = 996d76b7b4SDerek Schuff parseCustomSection(Sec, Sec.Content.data(), Sec.Content.size()))) 1002c6f75ddSDerek Schuff return; 1012c6f75ddSDerek Schuff } 1022c6f75ddSDerek Schuff Sections.push_back(Sec); 1032c6f75ddSDerek Schuff } 1042c6f75ddSDerek Schuff } 1052c6f75ddSDerek Schuff 1066d76b7b4SDerek Schuff Error WasmObjectFile::parseCustomSection(wasm::WasmSection &Sec, 1072c6f75ddSDerek Schuff const uint8_t *Ptr, size_t Length) { 1082c6f75ddSDerek Schuff Sec.Name = readString(Ptr); 1092c6f75ddSDerek Schuff return Error::success(); 1102c6f75ddSDerek Schuff } 1112c6f75ddSDerek Schuff 1122c6f75ddSDerek Schuff const uint8_t *WasmObjectFile::getPtr(size_t Offset) const { 1132c6f75ddSDerek Schuff return reinterpret_cast<const uint8_t *>(getData().substr(Offset, 1).data()); 1142c6f75ddSDerek Schuff } 1152c6f75ddSDerek Schuff 1162c6f75ddSDerek Schuff const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const { 1172c6f75ddSDerek Schuff return Header; 1182c6f75ddSDerek Schuff } 1192c6f75ddSDerek Schuff 1202c6f75ddSDerek Schuff void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { 1212c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 1222c6f75ddSDerek Schuff } 1232c6f75ddSDerek Schuff 1242c6f75ddSDerek Schuff std::error_code WasmObjectFile::printSymbolName(raw_ostream &OS, 1252c6f75ddSDerek Schuff DataRefImpl Symb) const { 1262c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 1272c6f75ddSDerek Schuff return object_error::invalid_symbol_index; 1282c6f75ddSDerek Schuff } 1292c6f75ddSDerek Schuff 1302c6f75ddSDerek Schuff uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { 1312c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 1322c6f75ddSDerek Schuff return 0; 1332c6f75ddSDerek Schuff } 1342c6f75ddSDerek Schuff 1352c6f75ddSDerek Schuff basic_symbol_iterator WasmObjectFile::symbol_begin() const { 1362c6f75ddSDerek Schuff return BasicSymbolRef(DataRefImpl(), this); 1372c6f75ddSDerek Schuff } 1382c6f75ddSDerek Schuff 1392c6f75ddSDerek Schuff basic_symbol_iterator WasmObjectFile::symbol_end() const { 1402c6f75ddSDerek Schuff return BasicSymbolRef(DataRefImpl(), this); 1412c6f75ddSDerek Schuff } 1422c6f75ddSDerek Schuff 1432c6f75ddSDerek Schuff Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const { 1442c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 1452c6f75ddSDerek Schuff return errorCodeToError(object_error::invalid_symbol_index); 1462c6f75ddSDerek Schuff } 1472c6f75ddSDerek Schuff 1482c6f75ddSDerek Schuff Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { 1492c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 1502c6f75ddSDerek Schuff return errorCodeToError(object_error::invalid_symbol_index); 1512c6f75ddSDerek Schuff } 1522c6f75ddSDerek Schuff 1532c6f75ddSDerek Schuff uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { 1542c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 1552c6f75ddSDerek Schuff return 0; 1562c6f75ddSDerek Schuff } 1572c6f75ddSDerek Schuff 1582c6f75ddSDerek Schuff uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const { 1592c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 1602c6f75ddSDerek Schuff return 0; 1612c6f75ddSDerek Schuff } 1622c6f75ddSDerek Schuff 1632c6f75ddSDerek Schuff uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { 1642c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 1652c6f75ddSDerek Schuff return 0; 1662c6f75ddSDerek Schuff } 1672c6f75ddSDerek Schuff 1682c6f75ddSDerek Schuff Expected<SymbolRef::Type> 1692c6f75ddSDerek Schuff WasmObjectFile::getSymbolType(DataRefImpl Symb) const { 1702c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 1712c6f75ddSDerek Schuff return errorCodeToError(object_error::invalid_symbol_index); 1722c6f75ddSDerek Schuff } 1732c6f75ddSDerek Schuff 1742c6f75ddSDerek Schuff Expected<section_iterator> 1752c6f75ddSDerek Schuff WasmObjectFile::getSymbolSection(DataRefImpl Symb) const { 1762c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 1772c6f75ddSDerek Schuff return errorCodeToError(object_error::invalid_symbol_index); 1782c6f75ddSDerek Schuff } 1792c6f75ddSDerek Schuff 1802c6f75ddSDerek Schuff void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; } 1812c6f75ddSDerek Schuff 1822c6f75ddSDerek Schuff std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec, 1832c6f75ddSDerek Schuff StringRef &Res) const { 1842c6f75ddSDerek Schuff const wasm::WasmSection &S = Sections[Sec.d.a]; 1852c6f75ddSDerek Schuff #define ECase(X) \ 1862c6f75ddSDerek Schuff case wasm::WASM_SEC_##X: \ 1872c6f75ddSDerek Schuff Res = #X; \ 1882c6f75ddSDerek Schuff break 1892c6f75ddSDerek Schuff switch (S.Type) { 1902c6f75ddSDerek Schuff ECase(TYPE); 1912c6f75ddSDerek Schuff ECase(IMPORT); 1922c6f75ddSDerek Schuff ECase(FUNCTION); 1932c6f75ddSDerek Schuff ECase(TABLE); 1942c6f75ddSDerek Schuff ECase(MEMORY); 1952c6f75ddSDerek Schuff ECase(GLOBAL); 1962c6f75ddSDerek Schuff ECase(EXPORT); 1972c6f75ddSDerek Schuff ECase(START); 1982c6f75ddSDerek Schuff ECase(ELEM); 1992c6f75ddSDerek Schuff ECase(CODE); 2002c6f75ddSDerek Schuff ECase(DATA); 2016d76b7b4SDerek Schuff case wasm::WASM_SEC_CUSTOM: 2022c6f75ddSDerek Schuff Res = S.Name; 2032c6f75ddSDerek Schuff break; 2042c6f75ddSDerek Schuff default: 2052c6f75ddSDerek Schuff return object_error::invalid_section_index; 2062c6f75ddSDerek Schuff } 2072c6f75ddSDerek Schuff #undef ECase 2082c6f75ddSDerek Schuff return std::error_code(); 2092c6f75ddSDerek Schuff } 2102c6f75ddSDerek Schuff 2112c6f75ddSDerek Schuff uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; } 2122c6f75ddSDerek Schuff 2132c6f75ddSDerek Schuff uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const { 2142c6f75ddSDerek Schuff const wasm::WasmSection &S = Sections[Sec.d.a]; 2152c6f75ddSDerek Schuff return S.Content.size(); 2162c6f75ddSDerek Schuff } 2172c6f75ddSDerek Schuff 2182c6f75ddSDerek Schuff std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec, 2192c6f75ddSDerek Schuff StringRef &Res) const { 2202c6f75ddSDerek Schuff const wasm::WasmSection &S = Sections[Sec.d.a]; 2212c6f75ddSDerek Schuff // This will never fail since wasm sections can never be empty (user-sections 2222c6f75ddSDerek Schuff // must have a name and non-user sections each have a defined structure). 2232c6f75ddSDerek Schuff Res = StringRef(reinterpret_cast<const char *>(S.Content.data()), 2242c6f75ddSDerek Schuff S.Content.size()); 2252c6f75ddSDerek Schuff return std::error_code(); 2262c6f75ddSDerek Schuff } 2272c6f75ddSDerek Schuff 2282c6f75ddSDerek Schuff uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const { 2292c6f75ddSDerek Schuff return 1; 2302c6f75ddSDerek Schuff } 2312c6f75ddSDerek Schuff 2322c6f75ddSDerek Schuff bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const { 2332c6f75ddSDerek Schuff return false; 2342c6f75ddSDerek Schuff } 2352c6f75ddSDerek Schuff 2362c6f75ddSDerek Schuff bool WasmObjectFile::isSectionText(DataRefImpl Sec) const { 2372c6f75ddSDerek Schuff const wasm::WasmSection &S = Sections[Sec.d.a]; 2382c6f75ddSDerek Schuff return S.Type == wasm::WASM_SEC_CODE; 2392c6f75ddSDerek Schuff } 2402c6f75ddSDerek Schuff 2412c6f75ddSDerek Schuff bool WasmObjectFile::isSectionData(DataRefImpl Sec) const { 2422c6f75ddSDerek Schuff const wasm::WasmSection &S = Sections[Sec.d.a]; 2432c6f75ddSDerek Schuff return S.Type == wasm::WASM_SEC_DATA; 2442c6f75ddSDerek Schuff } 2452c6f75ddSDerek Schuff 2462c6f75ddSDerek Schuff bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; } 2472c6f75ddSDerek Schuff 2482c6f75ddSDerek Schuff bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; } 2492c6f75ddSDerek Schuff 2502c6f75ddSDerek Schuff bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; } 2512c6f75ddSDerek Schuff 2522c6f75ddSDerek Schuff relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Sec) const { 2532c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 2542c6f75ddSDerek Schuff RelocationRef Rel; 2552c6f75ddSDerek Schuff return relocation_iterator(Rel); 2562c6f75ddSDerek Schuff } 2572c6f75ddSDerek Schuff 2582c6f75ddSDerek Schuff relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Sec) const { 2592c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 2602c6f75ddSDerek Schuff RelocationRef Rel; 2612c6f75ddSDerek Schuff return relocation_iterator(Rel); 2622c6f75ddSDerek Schuff } 2632c6f75ddSDerek Schuff 2642c6f75ddSDerek Schuff section_iterator WasmObjectFile::getRelocatedSection(DataRefImpl Sec) const { 2652c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 2662c6f75ddSDerek Schuff SectionRef Ref; 2672c6f75ddSDerek Schuff return section_iterator(Ref); 2682c6f75ddSDerek Schuff } 2692c6f75ddSDerek Schuff 2702c6f75ddSDerek Schuff void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { 2712c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 2722c6f75ddSDerek Schuff } 2732c6f75ddSDerek Schuff 2742c6f75ddSDerek Schuff uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Rel) const { 2752c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 2762c6f75ddSDerek Schuff return 0; 2772c6f75ddSDerek Schuff } 2782c6f75ddSDerek Schuff 2792c6f75ddSDerek Schuff symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const { 2802c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 2812c6f75ddSDerek Schuff SymbolRef Ref; 2822c6f75ddSDerek Schuff return symbol_iterator(Ref); 2832c6f75ddSDerek Schuff } 2842c6f75ddSDerek Schuff 2852c6f75ddSDerek Schuff uint64_t WasmObjectFile::getRelocationType(DataRefImpl Rel) const { 2862c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 2872c6f75ddSDerek Schuff return 0; 2882c6f75ddSDerek Schuff } 2892c6f75ddSDerek Schuff 2902c6f75ddSDerek Schuff void WasmObjectFile::getRelocationTypeName( 2912c6f75ddSDerek Schuff DataRefImpl Rel, SmallVectorImpl<char> &Result) const { 2922c6f75ddSDerek Schuff llvm_unreachable("not yet implemented"); 2932c6f75ddSDerek Schuff } 2942c6f75ddSDerek Schuff 2952c6f75ddSDerek Schuff section_iterator WasmObjectFile::section_begin() const { 2962c6f75ddSDerek Schuff DataRefImpl Ref; 2972c6f75ddSDerek Schuff Ref.d.a = 0; 2982c6f75ddSDerek Schuff return section_iterator(SectionRef(Ref, this)); 2992c6f75ddSDerek Schuff } 3002c6f75ddSDerek Schuff 3012c6f75ddSDerek Schuff section_iterator WasmObjectFile::section_end() const { 3022c6f75ddSDerek Schuff DataRefImpl Ref; 3032c6f75ddSDerek Schuff Ref.d.a = Sections.size(); 3042c6f75ddSDerek Schuff return section_iterator(SectionRef(Ref, this)); 3052c6f75ddSDerek Schuff } 3062c6f75ddSDerek Schuff 3072c6f75ddSDerek Schuff uint8_t WasmObjectFile::getBytesInAddress() const { return 4; } 3082c6f75ddSDerek Schuff 3092c6f75ddSDerek Schuff StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; } 3102c6f75ddSDerek Schuff 3112c6f75ddSDerek Schuff unsigned WasmObjectFile::getArch() const { return Triple::wasm32; } 3122c6f75ddSDerek Schuff 3132c6f75ddSDerek Schuff SubtargetFeatures WasmObjectFile::getFeatures() const { 3142c6f75ddSDerek Schuff return SubtargetFeatures(); 3152c6f75ddSDerek Schuff } 3162c6f75ddSDerek Schuff 3172c6f75ddSDerek Schuff bool WasmObjectFile::isRelocatableObject() const { return false; } 3182c6f75ddSDerek Schuff 3192c6f75ddSDerek Schuff const wasm::WasmSection * 3202c6f75ddSDerek Schuff WasmObjectFile::getWasmSection(const SectionRef &Section) const { 3212c6f75ddSDerek Schuff return &Sections[Section.getRawDataRefImpl().d.a]; 3222c6f75ddSDerek Schuff } 323