Index: include/llvm/Object/Wasm.h =================================================================== --- include/llvm/Object/Wasm.h +++ include/llvm/Object/Wasm.h @@ -203,6 +203,8 @@ SubtargetFeatures getFeatures() const override; bool isRelocatableObject() const override; + bool isSectionWasmDataSegment(const SectionRef &Section) const; + private: bool isValidFunctionIndex(uint32_t Index) const; bool isDefinedFunctionIndex(uint32_t Index) const; @@ -211,6 +213,10 @@ const WasmSection &getWasmSection(DataRefImpl Ref) const; const wasm::WasmRelocation &getWasmRelocation(DataRefImpl Ref) const; + bool isSectionWasmDataSegment(DataRefImpl Sec) const; + + const wasm::WasmDataSegment &getSectionWasmDataSegment(DataRefImpl Ref) const; + WasmSection* findCustomSectionByName(StringRef Name); WasmSection* findSectionByType(uint32_t Type); Index: lib/MC/WasmObjectWriter.cpp =================================================================== --- lib/MC/WasmObjectWriter.cpp +++ lib/MC/WasmObjectWriter.cpp @@ -291,6 +291,12 @@ void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef Functions); void writeDataSection(ArrayRef Segments); + + void writeAlignedDataSegment(SectionBookkeeping &Section, const WasmDataSegment & Segment); + void writeDataSegment(SectionBookkeeping &Section, const WasmDataSegment & Segment, + unsigned MemIndexPadTo = 0, unsigned OffsetPadTo = 0, + unsigned SizePadTo = 0); + void writeCodeRelocSection(); void writeDataRelocSection(); void writeLinkingMetaDataSection( @@ -834,13 +840,13 @@ encodeULEB128(Segments.size(), getStream()); // count for (const WasmDataSegment & Segment : Segments) { - encodeULEB128(0, getStream()); // memory index - write8(wasm::WASM_OPCODE_I32_CONST); - encodeSLEB128(Segment.Offset, getStream()); // offset - write8(wasm::WASM_OPCODE_END); - encodeULEB128(Segment.Data.size(), getStream()); // size - Segment.Section->setSectionOffset(getStream().tell() - Section.ContentsOffset); - writeBytes(Segment.Data); // data + + // although WASM format is not supposed to designed to be mapped into memory + // some certain sections are expected to aligned. + if (Segment.Name == "__clangast") + writeAlignedDataSegment(Section, Segment); + else + writeDataSegment(Section, Segment); } // Apply fixups. @@ -849,11 +855,60 @@ endSection(Section); } +void WasmObjectWriter::writeAlignedDataSegment(SectionBookkeeping &Section, + const WasmDataSegment &Segment) { + // alignment is done by padding extra 0 in the ULEB encoded integers + // namely memoryIndex, offset and size + + // ULEB128 encoding is limited to 10 bytes. +#define MAX_PAD_TO (10) // 64-bit integer is encoded as 10 7-bit elements + + raw_null_ostream NullStream; + unsigned MemIndexLen = encodeULEB128(0, NullStream); + unsigned OffsetLen = encodeSLEB128(Segment.Offset, NullStream); + unsigned SizeLen = encodeULEB128(Segment.Data.size(), NullStream); + + // 2 = the 2-bytes for WASM_OPCODE_I32_CONST and WASM_OPCODE_END + uint64_t SegmentStart = + (getStream().tell() + MemIndexLen + OffsetLen + SizeLen + 2); + uint64_t RemainingPadding = + OffsetToAlignment(SegmentStart, Segment.Alignment); + + // now divide Padding between MemIndex, Offset and Size + unsigned MemIndexPadTo = MemIndexLen + RemainingPadding; + if (MemIndexPadTo > MAX_PAD_TO) MemIndexPadTo = MAX_PAD_TO; + RemainingPadding = RemainingPadding - (MemIndexPadTo - MemIndexLen); + unsigned OffsetPadTo = OffsetLen + RemainingPadding; + if (OffsetPadTo > MAX_PAD_TO) OffsetPadTo = MAX_PAD_TO; + RemainingPadding = RemainingPadding - (OffsetPadTo - OffsetLen); + unsigned SizePadTo = SizeLen + RemainingPadding; + assert(SizePadTo < MAX_PAD_TO && "Unable to align data segment"); + + writeDataSegment(Section, Segment, MemIndexPadTo, OffsetPadTo, SizePadTo); +} + +void WasmObjectWriter::writeDataSegment(SectionBookkeeping &Section, + const WasmDataSegment &Segment, + unsigned MemIndexPadTo, + unsigned OffsetPadTo, + unsigned SizePadTo) { + encodeULEB128(0, getStream(), MemIndexPadTo); // memory index + write8(wasm::WASM_OPCODE_I32_CONST); + encodeSLEB128(Segment.Offset, getStream(), OffsetPadTo); // offset + write8(wasm::WASM_OPCODE_END); + + encodeULEB128(Segment.Data.size(), getStream(), SizePadTo); // size + + Segment.Section->setSectionOffset(getStream().tell() - + Section.ContentsOffset); + writeBytes(Segment.Data); // data +} + void WasmObjectWriter::writeCodeRelocSection() { // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md // for descriptions of the reloc sections. - if (CodeRelocations.empty()) + if (CodeRelocations.empty()) return; SectionBookkeeping Section; @@ -871,7 +926,7 @@ // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md // for descriptions of the reloc sections. - if (DataRelocations.empty()) + if (DataRelocations.empty()) return; SectionBookkeeping Section; Index: lib/Object/WasmObjectFile.cpp =================================================================== --- lib/Object/WasmObjectFile.cpp +++ lib/Object/WasmObjectFile.cpp @@ -991,7 +991,14 @@ return section_iterator(SectionRef(Ref, this)); } -void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; } +void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { + if (isSectionData(Sec) && (Sec.d.b < DataSegments.size())) { + Sec.d.b++; + } else { + Sec.d.a++; + Sec.d.b = 0; + } +} std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec, StringRef &Res) const { @@ -1011,7 +1018,13 @@ ECase(START); ECase(ELEM); ECase(CODE); - ECase(DATA); + case wasm::WASM_SEC_DATA: { + if (isSectionWasmDataSegment(Sec)) + Res = getSectionWasmDataSegment(Sec).Name; + else + Res = "DATA"; + break; + } case wasm::WASM_SEC_CUSTOM: Res = S.Name; break; @@ -1029,22 +1042,46 @@ } uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const { - const WasmSection &S = Sections[Sec.d.a]; - return S.Content.size(); + StringRef Res; + getSectionContents(Sec, Res); + return Res.size(); } std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec, StringRef &Res) const { - const WasmSection &S = Sections[Sec.d.a]; + const auto &Content = isSectionWasmDataSegment(Sec) + ? getSectionWasmDataSegment(Sec).Content + : getWasmSection(Sec).Content; + // This will never fail since wasm sections can never be empty (user-sections // must have a name and non-user sections each have a defined structure). - Res = StringRef(reinterpret_cast(S.Content.data()), - S.Content.size()); + Res = StringRef(reinterpret_cast(Content.data()), + Content.size()); return std::error_code(); } uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const { - return 1; + if (isSectionData(Sec)) { + const wasm::WasmDataSegment &Data = getSectionWasmDataSegment(Sec); + return Data.Alignment; + } + + return 1; +} + +bool WasmObjectFile::isSectionWasmDataSegment(DataRefImpl Sec) const { + return isSectionData(Sec) && Sec.d.b != 0; +} + +bool WasmObjectFile::isSectionWasmDataSegment(const SectionRef &Section) const { + return isSectionWasmDataSegment(Section.getRawDataRefImpl()); +} + +const wasm::WasmDataSegment &WasmObjectFile::getSectionWasmDataSegment(DataRefImpl Sec) const { + assert(isSectionData(Sec) && "Section should be Data"); + assert(Sec.d.b > 0); + assert(Sec.d.b <= DataSegments.size()); + return DataSegments[Sec.d.b-1].Data; } bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const { @@ -1076,7 +1113,14 @@ const WasmSection &Sec = getWasmSection(Ref); DataRefImpl RelocRef; RelocRef.d.a = Ref.d.a; - RelocRef.d.b = Sec.Relocations.size(); + + // if Ref is pointing to a "Section" that proxy to a Data Segment, + // don't expose the relocation table + if (isSectionWasmDataSegment(Ref)) + RelocRef.d.b = 0; + else + RelocRef.d.b = Sec.Relocations.size(); + return relocation_iterator(RelocationRef(RelocRef, this)); } Index: test/tools/llvm-objdump/WebAssembly/symbol-table.test =================================================================== --- test/tools/llvm-objdump/WebAssembly/symbol-table.test +++ test/tools/llvm-objdump/WebAssembly/symbol-table.test @@ -4,5 +4,6 @@ CHECK-NEXT: 00000000 g F IMPORT puts CHECK-NEXT: 00000000 g F IMPORT SomeOtherFunction CHECK-NEXT: 00000002 g F EXPORT main +CHECK-NEXT: 00000000 l EXPORT .L.str CHECK-NEXT: 00000010 g EXPORT var Index: test/tools/llvm-objdump/wasm.txt =================================================================== --- test/tools/llvm-objdump/wasm.txt +++ test/tools/llvm-objdump/wasm.txt @@ -2,18 +2,17 @@ # CHECK: Sections: # CHECK-NEXT: Idx Name Size Address Type -# CHECK-NEXT: 0 TYPE 0000000e 0000000000000000 -# CHECK-NEXT: 1 IMPORT 00000024 0000000000000000 -# CHECK-NEXT: 2 FUNCTION 00000002 0000000000000000 -# CHECK-NEXT: 3 TABLE 00000004 0000000000000000 -# CHECK-NEXT: 4 MEMORY 00000003 0000000000000000 -# CHECK-NEXT: 5 GLOBAL 0000000b 0000000000000000 -# CHECK-NEXT: 6 EXPORT 0000000e 0000000000000000 -# CHECK-NEXT: 7 CODE 00000019 0000000000000000 TEXT -# CHECK-NEXT: 8 DATA 0000001a 0000000000000000 DATA -# CHECK-NEXT: 9 name 0000002b 0000000000000000 -# CHECK-NEXT: 10 reloc.CODE 00000017 0000000000000000 -# CHECK-NEXT: 11 linking 00000016 0000000000000000 +# CHECK-NEXT: 0 TYPE 0000000e 0000000000000000 +# CHECK-NEXT: 1 IMPORT 0000005d 0000000000000000 +# CHECK-NEXT: 2 FUNCTION 00000002 0000000000000000 +# CHECK-NEXT: 3 GLOBAL 0000000b 0000000000000000 +# CHECK-NEXT: 4 EXPORT 00000017 0000000000000000 +# CHECK-NEXT: 5 CODE 00000019 0000000000000000 TEXT +# CHECK-NEXT: 6 DATA 0000001c 0000000000000000 DATA +# CHECK-NEXT: 7 .rodata..L.str 0000000d 0000000000000000 DATA +# CHECK-NEXT: 8 .bss.var 00000004 0000000000000000 +# CHECK-NEXT: 9 reloc.CODE 00000017 0000000000000000 +# CHECK-NEXT: 10 linking 00000041 0000000000000000 # RUN: llvm-objdump -p %p/Inputs/trivial.obj.wasm | FileCheck %s -check-prefix CHECK-HEADER Index: tools/llvm-readobj/WasmDumper.cpp =================================================================== --- tools/llvm-readobj/WasmDumper.cpp +++ tools/llvm-readobj/WasmDumper.cpp @@ -144,6 +144,8 @@ void WasmDumper::printSections() { ListScope Group(W, "Sections"); for (const SectionRef &Section : Obj->sections()) { + if (Obj->isSectionWasmDataSegment(Section)) + continue; const WasmSection &WasmSec = Obj->getWasmSection(Section); DictScope SectionD(W, "Section"); W.printEnum("Type", WasmSec.Type, makeArrayRef(WasmSectionTypes)); Index: tools/obj2yaml/wasm2yaml.cpp =================================================================== --- tools/obj2yaml/wasm2yaml.cpp +++ tools/obj2yaml/wasm2yaml.cpp @@ -259,6 +259,8 @@ break; } case wasm::WASM_SEC_DATA: { + if (Obj.isSectionWasmDataSegment(Sec)) + continue; auto DataSec = make_unique(); for (const object::WasmSegment &Segment : Obj.dataSegments()) { WasmYAML::DataSegment Seg;