[WebAssembly] Add support for naming wasm data segments
authorSam Clegg <sbc@chromium.org>
Tue, 19 Sep 2017 23:00:57 +0000 (23:00 +0000)
committerSam Clegg <sbc@chromium.org>
Tue, 19 Sep 2017 23:00:57 +0000 (23:00 +0000)
Add adds support for naming data segments.  This is useful
useful linkers so that they can merge similar sections.

Differential Revision: https://reviews.llvm.org/D37886

llvm-svn: 313692

14 files changed:
llvm/include/llvm/BinaryFormat/Wasm.h
llvm/include/llvm/ObjectYAML/WasmYAML.h
llvm/lib/MC/WasmObjectWriter.cpp
llvm/lib/Object/WasmObjectFile.cpp
llvm/lib/ObjectYAML/WasmYAML.cpp
llvm/test/MC/WebAssembly/array-fill.ll
llvm/test/MC/WebAssembly/bss.ll [new file with mode: 0644]
llvm/test/MC/WebAssembly/explicit-sections.ll
llvm/test/MC/WebAssembly/unnamed-data.ll
llvm/test/MC/WebAssembly/weak-alias.ll
llvm/test/tools/llvm-readobj/sections.test
llvm/tools/llvm-readobj/WasmDumper.cpp
llvm/tools/obj2yaml/wasm2yaml.cpp
llvm/tools/yaml2obj/yaml2wasm.cpp

index 23e30b7..53a812b 100644 (file)
@@ -97,6 +97,7 @@ struct WasmDataSegment {
   uint32_t MemoryIndex;
   WasmInitExpr Offset;
   ArrayRef<uint8_t> Content;
+  StringRef Name;
 };
 
 struct WasmElemSegment {
@@ -184,6 +185,7 @@ enum : unsigned {
   WASM_SYMBOL_INFO    = 0x2,
   WASM_DATA_SIZE      = 0x3,
   WASM_DATA_ALIGNMENT = 0x4,
+  WASM_SEGMENT_NAMES  = 0x5,
 };
 
 enum : unsigned {
index 709ad8e..171f823 100644 (file)
@@ -160,9 +160,10 @@ struct LinkingSection : CustomSection {
     return C && C->Name == "linking";
   }
 
-  std::vector<SymbolInfo> SymbolInfos;
   uint32_t DataSize;
   uint32_t DataAlignment;
+  std::vector<SymbolInfo> SymbolInfos;
+  std::vector<NameEntry> SegmentNames;
 };
 
 struct TypeSection : Section {
index 7ed20d3..6ec9324 100644 (file)
@@ -102,6 +102,7 @@ struct WasmFunctionTypeDenseMapInfo {
 // wasm data segment.
 struct WasmDataSegment {
   MCSectionWasm *Section;
+  StringRef Name;
   uint32_t Offset;
   SmallVector<char, 4> Data;
 };
@@ -279,7 +280,8 @@ private:
                         uint32_t NumFuncImports);
   void writeCodeRelocSection();
   void writeDataRelocSection();
-  void writeLinkingMetaDataSection(uint32_t DataSize, uint32_t DataAlignment,
+  void writeLinkingMetaDataSection(ArrayRef<WasmDataSegment> Segments,
+                                   uint32_t DataSize, uint32_t DataAlignment,
                                    ArrayRef<StringRef> WeakSymbols,
                                    bool HasStackPointer,
                                    uint32_t StackPointerGlobal);
@@ -911,7 +913,8 @@ void WasmObjectWriter::writeDataRelocSection() {
 }
 
 void WasmObjectWriter::writeLinkingMetaDataSection(
-    uint32_t DataSize, uint32_t DataAlignment, ArrayRef<StringRef> WeakSymbols,
+    ArrayRef<WasmDataSegment> Segments, uint32_t DataSize,
+    uint32_t DataAlignment, ArrayRef<StringRef> WeakSymbols,
     bool HasStackPointer, uint32_t StackPointerGlobal) {
   SectionBookkeeping Section;
   startSection(Section, wasm::WASM_SEC_CUSTOM, "linking");
@@ -943,6 +946,14 @@ void WasmObjectWriter::writeLinkingMetaDataSection(
     endSection(SubSection);
   }
 
+  if (Segments.size()) {
+    startSection(SubSection, wasm::WASM_SEGMENT_NAMES);
+    encodeULEB128(Segments.size(), getStream());
+    for (const WasmDataSegment &Segment : Segments)
+      writeString(Segment.Name);
+    endSection(SubSection);
+  }
+
   endSection(Section);
 }
 
@@ -1129,6 +1140,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
     DataSize = alignTo(DataSize, Section.getAlignment());
     DataSegments.emplace_back();
     WasmDataSegment &Segment = DataSegments.back();
+    Segment.Name = Section.getSectionName();
     Segment.Offset = DataSize;
     Segment.Section = &Section;
     addData(Segment.Data, Section, DataAlignment);
@@ -1288,7 +1300,8 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
   writeNameSection(Functions, Imports, NumFuncImports);
   writeCodeRelocSection();
   writeDataRelocSection();
-  writeLinkingMetaDataSection(DataSize, DataAlignment, WeakSymbols, HasStackPointer, StackPointerGlobal);
+  writeLinkingMetaDataSection(DataSegments, DataSize, DataAlignment,
+                              WeakSymbols, HasStackPointer, StackPointerGlobal);
 
   // TODO: Translate the .comment section to the output.
   // TODO: Translate debug sections to the output.
index bd51fbd..d2d3aba 100644 (file)
@@ -396,6 +396,15 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr,
     case wasm::WASM_DATA_ALIGNMENT:
       LinkingData.DataAlignment = readVaruint32(Ptr);
       break;
+    case wasm::WASM_SEGMENT_NAMES: {
+      uint32_t Count = readVaruint32(Ptr);
+      if (Count > DataSegments.size())
+        return make_error<GenericBinaryError>("Too many segment names",
+                                              object_error::parse_failed);
+      for (uint32_t i = 0; i < Count; i++)
+        DataSegments[i].Data.Name = readString(Ptr);
+      break;
+    }
     case wasm::WASM_STACK_POINTER:
     default:
       Ptr += Size;
index 8aea8cf..a5c1d13 100644 (file)
@@ -60,6 +60,7 @@ static void sectionMapping(IO &IO, WasmYAML::LinkingSection &Section) {
   IO.mapRequired("DataSize", Section.DataSize);
   IO.mapRequired("DataAlignment", Section.DataAlignment);
   IO.mapOptional("SymbolInfo", Section.SymbolInfos);
+  IO.mapOptional("SegmentNames", Section.SegmentNames);
 }
 
 static void sectionMapping(IO &IO, WasmYAML::CustomSection &Section) {
index 4feabc0..38274c3 100644 (file)
@@ -9,6 +9,14 @@ target triple = "wasm32-unknown-unknown-wasm"
 
 @gBd = hidden global [2 x %struct.bd] [%struct.bd { i8 1 }, %struct.bd { i8 2 }], align 1
 
-; CHECK:  - Type:            DATA
-; CHECK:        Content:         '0102'
-; CHECK:    DataSize:        2
+; CHECK:        - Type:            DATA
+; CHECK:              Content:         '0102'
+
+; CHECK:        - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        2
+; CHECK-NEXT:     DataAlignment:   1
+; CHECK-NEXT:     SegmentNames:    
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            .data
+; CHECK-NEXT: ...
diff --git a/llvm/test/MC/WebAssembly/bss.ll b/llvm/test/MC/WebAssembly/bss.ll
new file mode 100644 (file)
index 0000000..d203efa
--- /dev/null
@@ -0,0 +1,20 @@
+; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj %s -o - | obj2yaml | FileCheck %s
+
+@g0 = global i8* null, align 4
+
+; CHECK:        - Type:            DATA
+; CHECK-NEXT:     Segments:        
+; CHECK-NEXT:       - SectionOffset:   6
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           0
+; CHECK-NEXT:         Content:         '00000000'
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        4
+; CHECK-NEXT:     DataAlignment:   4
+; CHECK-NEXT:     SegmentNames:    
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            .bss.g0
+; CHECK-NEXT: ...
index e960724..a8342b6 100644 (file)
 ; CHECK-NEXT:           Opcode:          I32_CONST
 ; CHECK-NEXT:           Value:           24
 ; CHECK-NEXT:         Content:         '08000000'
+
+; CHECK:        - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        28
+; CHECK-NEXT:     DataAlignment:   8
+; CHECK-NEXT:     SegmentNames:    
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            .data.global0
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         Name:            .sec1
+; CHECK-NEXT:       - Index:           2
+; CHECK-NEXT:         Name:            .sec2
+; CHECK-NEXT: ...
index b5f6d3c..a484913 100644 (file)
 ; CHECK-NEXT:     Name:            linking
 ; CHECK-NEXT:     DataSize:        28
 ; CHECK-NEXT:     DataAlignment:   8
+; CHECK-NEXT:     SegmentNames:    
+; CHECK-NEXT:       - Index:       0
+; CHECK-NEXT:         Name:        .rodata..L.str1
+; CHECK-NEXT:       - Index:       1
+; CHECK-NEXT:         Name:        .rodata..L.str2
+; CHECK-NEXT:       - Index:       2
+; CHECK-NEXT:         Name:        .data.a
+; CHECK-NEXT:       - Index:       3
+; CHECK-NEXT:         Name:        .data.b
 ; CHECK-NEXT: ...
index 79c597b..2beef84 100644 (file)
@@ -101,4 +101,9 @@ entry:
 ; CHECK-NEXT:         Flags:           1
 ; CHECK-NEXT:       - Name:            bar_alias
 ; CHECK-NEXT:         Flags:           1
+; CHECK-NEXT:     SegmentNames:    
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            .data.bar
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         Name:            .data.bar_alias_address
 ; CHECK-NEXT: ...
index 4eda5da..ac1eca5 100644 (file)
@@ -543,6 +543,12 @@ WASM-NEXT:   Section {
 WASM-NEXT:     Type: DATA (0xB)
 WASM-NEXT:     Size: 19
 WASM-NEXT:     Offset: 154
+WASM-NEXT:     Segments [
+WASM-NEXT:       Segment {
+WASM-NEXT:         Size: 13
+WASM-NEXT:         Offset: 0
+WASM-NEXT:       }
+WASM-NEXT:     ]
 WASM-NEXT:   }
 WASM-NEXT:   Section {
 WASM-NEXT:     Type: CUSTOM (0x0)
index 88fcbf6..3be1f82 100644 (file)
@@ -160,6 +160,18 @@ void WasmDumper::printSections() {
           W.printNumber("DataAlignment", LinkingData.DataAlignment);
       }
       break;
+    case wasm::WASM_SEC_DATA: {
+      ListScope Group(W, "Segments");
+      for (const WasmSegment &Segment : Obj->dataSegments()) {
+        DictScope Group(W, "Segment");
+        if (!Segment.Data.Name.empty())
+          W.printString("Name", Segment.Data.Name);
+        W.printNumber("Size", Segment.Data.Content.size());
+        if (Segment.Data.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST)
+          W.printNumber("Offset", Segment.Data.Offset.Value.Int32);
+      }
+      break;
+    }
     case wasm::WASM_SEC_MEMORY:
       ListScope Group(W, "Memories");
       for (const wasm::WasmLimits &Memory : Obj->memories()) {
index a1da4b6..8b2a0ad 100644 (file)
@@ -70,6 +70,16 @@ std::unique_ptr<WasmYAML::CustomSection> WasmDumper::dumpCustomSection(const Was
     CustomSec = std::move(NameSec);
   } else if (WasmSec.Name == "linking") {
     std::unique_ptr<WasmYAML::LinkingSection> LinkingSec = make_unique<WasmYAML::LinkingSection>();
+    size_t Index = 0;
+    for (const object::WasmSegment &Segment : Obj.dataSegments()) {
+      if (!Segment.Data.Name.empty()) {
+        WasmYAML::NameEntry NameEntry;
+        NameEntry.Name = Segment.Data.Name;
+        NameEntry.Index = Index;
+        LinkingSec->SegmentNames.push_back(NameEntry);
+      }
+      Index++;
+    }
     for (const object::SymbolRef& Sym: Obj.symbols()) {
       const object::WasmSymbol Symbol = Obj.getWasmSymbol(Sym);
       if (Symbol.Flags != 0) {
@@ -234,7 +244,7 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
     }
     case wasm::WASM_SEC_DATA: {
       auto DataSec = make_unique<WasmYAML::DataSection>();
-      for (auto &Segment : Obj.dataSegments()) {
+      for (const object::WasmSegment &Segment : Obj.dataSegments()) {
         WasmYAML::DataSegment Seg;
         Seg.SectionOffset = Segment.SectionOffset;
         Seg.MemoryIndex = Segment.Data.MemoryIndex;
index 0bd8829..9dd7564 100644 (file)
@@ -157,6 +157,17 @@ int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &S
 
     SubSection.Done();
   }
+
+  // SEGMENT_NAMES subsection
+  if (Section.SegmentNames.size()) {
+    encodeULEB128(wasm::WASM_SEGMENT_NAMES, OS);
+    encodeULEB128(Section.SegmentNames.size(), SubSection.GetStream());
+    for (const WasmYAML::NameEntry &NameEntry : Section.SegmentNames) {
+      encodeULEB128(NameEntry.Index, SubSection.GetStream());
+      writeStringRef(NameEntry.Name, SubSection.GetStream());
+    }
+    SubSection.Done();
+  }
   return 0;
 }