[WebAssembly] Add data size and alignement to linking section

The overal size of the data section (including BSS)
is otherwise not included in the wasm binary.

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

llvm-svn: 306459
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 470c20d..eef473b 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -112,6 +112,11 @@
   int64_t Addend;  // A value to add to the symbol.
 };
 
+struct WasmLinkingData {
+  uint32_t DataSize;
+  uint32_t DataAlignment;
+};
+
 enum : unsigned {
   WASM_SEC_CUSTOM = 0,   // Custom / User-defined section
   WASM_SEC_TYPE = 1,     // Function signature declarations
@@ -175,8 +180,10 @@
 
 // Linking metadata kinds.
 enum : unsigned {
-  WASM_STACK_POINTER = 0x1,
-  WASM_SYMBOL_INFO  = 0x2,
+  WASM_STACK_POINTER  = 0x1,
+  WASM_SYMBOL_INFO    = 0x2,
+  WASM_DATA_SIZE      = 0x3,
+  WASM_DATA_ALIGNMENT = 0x4,
 };
 
 enum : unsigned {
diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h
index 9d53131..cfad7e2 100644
--- a/llvm/include/llvm/Object/Wasm.h
+++ b/llvm/include/llvm/Object/Wasm.h
@@ -100,6 +100,7 @@
   const std::vector<wasm::WasmLimits>& memories() const { return Memories; }
   const std::vector<wasm::WasmGlobal>& globals() const { return Globals; }
   const std::vector<wasm::WasmExport>& exports() const { return Exports; }
+  const wasm::WasmLinkingData& linkingData() const { return LinkingData; }
 
   uint32_t getNumberOfSymbols() const {
     return Symbols.size();
@@ -214,6 +215,7 @@
   std::vector<WasmSymbol> Symbols;
   ArrayRef<uint8_t> CodeSection;
   uint32_t StartFunction = -1;
+  wasm::WasmLinkingData LinkingData;
 
   StringMap<uint32_t> SymbolMap;
 };
diff --git a/llvm/include/llvm/ObjectYAML/WasmYAML.h b/llvm/include/llvm/ObjectYAML/WasmYAML.h
index 74f5664..d508484 100644
--- a/llvm/include/llvm/ObjectYAML/WasmYAML.h
+++ b/llvm/include/llvm/ObjectYAML/WasmYAML.h
@@ -154,6 +154,8 @@
   }
 
   std::vector<SymbolInfo> SymbolInfos;
+  uint32_t DataSize;
+  uint32_t DataAlignment;
 };
 
 struct TypeSection : Section {
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index 45534ba..82352cb 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -265,7 +265,8 @@
                         uint32_t NumFuncImports);
   void writeCodeRelocSection();
   void writeDataRelocSection(uint64_t DataSectionHeaderSize);
-  void writeLinkingMetaDataSection(ArrayRef<StringRef> WeakSymbols,
+  void writeLinkingMetaDataSection(uint32_t DataSize, uint32_t DataAlignment,
+                                   ArrayRef<StringRef> WeakSymbols,
                                    bool HasStackPointer,
                                    uint32_t StackPointerGlobal);
 
@@ -877,11 +878,8 @@
 }
 
 void WasmObjectWriter::writeLinkingMetaDataSection(
-    ArrayRef<StringRef> WeakSymbols, bool HasStackPointer,
-    uint32_t StackPointerGlobal) {
-  if (!HasStackPointer && WeakSymbols.empty())
-    return;
-
+    uint32_t DataSize, uint32_t DataAlignment, ArrayRef<StringRef> WeakSymbols,
+    bool HasStackPointer, uint32_t StackPointerGlobal) {
   SectionBookkeeping Section;
   startSection(Section, wasm::WASM_SEC_CUSTOM, "linking");
   SectionBookkeeping SubSection;
@@ -902,6 +900,16 @@
     endSection(SubSection);
   }
 
+  if (DataSize > 0) {
+    startSection(SubSection, wasm::WASM_DATA_SIZE);
+    encodeULEB128(DataSize, getStream());
+    endSection(SubSection);
+
+    startSection(SubSection, wasm::WASM_DATA_ALIGNMENT);
+    encodeULEB128(DataAlignment, getStream());
+    endSection(SubSection);
+  }
+
   endSection(Section);
 }
 
@@ -923,6 +931,7 @@
   unsigned NumFuncImports = 0;
   unsigned NumGlobalImports = 0;
   SmallVector<char, 0> DataBytes;
+  uint32_t DataAlignment = 1;
   uint32_t StackPointerGlobal = 0;
   bool HasStackPointer = false;
 
@@ -1157,6 +1166,7 @@
         report_fatal_error("data sections must contain at most one variable");
 
       DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
+      DataAlignment = std::max(DataAlignment, DataSection.getAlignment());
 
       DataSection.setSectionOffset(DataBytes.size());
 
@@ -1272,7 +1282,7 @@
   writeNameSection(Functions, Imports, NumFuncImports);
   writeCodeRelocSection();
   writeDataRelocSection(DataSectionHeaderSize);
-  writeLinkingMetaDataSection(WeakSymbols, HasStackPointer, StackPointerGlobal);
+  writeLinkingMetaDataSection(DataBytes.size(), DataAlignment, WeakSymbols, HasStackPointer, StackPointerGlobal);
 
   // TODO: Translate the .comment section to the output.
   // TODO: Translate debug sections to the output.
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index d158606..e87dd48 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -193,6 +193,9 @@
 
 WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
     : ObjectFile(Binary::ID_Wasm, Buffer) {
+  LinkingData.DataAlignment = 0;
+  LinkingData.DataSize = 0;
+
   ErrorAsOutParameter ErrAsOutParam(&Err);
   Header.Magic = getData().substr(0, 4);
   if (Header.Magic != StringRef("\0asm", 4)) {
@@ -305,7 +308,7 @@
         auto iter = SymbolMap.find(Symbol);
         if (iter == SymbolMap.end()) {
           return make_error<GenericBinaryError>(
-              "Invalid symbol name in linking section",
+              "Invalid symbol name in linking section: " + Symbol,
               object_error::parse_failed);
         }
         uint32_t SymIndex = iter->second;
@@ -318,6 +321,12 @@
       }
       break;
     }
+    case wasm::WASM_DATA_SIZE:
+      LinkingData.DataSize = readVaruint32(Ptr);
+      break;
+    case wasm::WASM_DATA_ALIGNMENT:
+      LinkingData.DataAlignment = readVaruint32(Ptr);
+      break;
     case wasm::WASM_STACK_POINTER:
     default:
       Ptr += Size;
diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp
index 65703c6..1199955 100644
--- a/llvm/lib/ObjectYAML/WasmYAML.cpp
+++ b/llvm/lib/ObjectYAML/WasmYAML.cpp
@@ -56,6 +56,8 @@
 static void sectionMapping(IO &IO, WasmYAML::LinkingSection &Section) {
   commonSectionMapping(IO, Section);
   IO.mapRequired("Name", Section.Name);
+  IO.mapRequired("DataSize", Section.DataSize);
+  IO.mapRequired("DataAlignment", Section.DataAlignment);
   IO.mapRequired("SymbolInfo", Section.SymbolInfos);
 }
 
diff --git a/llvm/test/MC/WebAssembly/unnamed-data.ll b/llvm/test/MC/WebAssembly/unnamed-data.ll
index 77a7c08..fd98508 100644
--- a/llvm/test/MC/WebAssembly/unnamed-data.ll
+++ b/llvm/test/MC/WebAssembly/unnamed-data.ll
@@ -7,47 +7,53 @@
 @b = global i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str2, i32 0, i32 0), align 8
 
 
-; CHECK:   - Type:            GLOBAL
-; CHECK:     Globals:         
-; CHECK:       - Type:            I32
-; CHECK:         Mutable:         false
-; CHECK:         InitExpr:        
-; CHECK:           Opcode:          I32_CONST
-; CHECK:           Value:           0
-; CHECK:       - Type:            I32
-; CHECK:         Mutable:         false
-; CHECK:         InitExpr:        
-; CHECK:           Opcode:          I32_CONST
-; CHECK:           Value:           6
-; CHECK:       - Type:            I32
-; CHECK:         Mutable:         false
-; CHECK:         InitExpr:        
-; CHECK:           Opcode:          I32_CONST
-; CHECK:           Value:           16
-; CHECK:       - Type:            I32
-; CHECK:         Mutable:         false
-; CHECK:         InitExpr:        
-; CHECK:           Opcode:          I32_CONST
-; CHECK:           Value:           24
-; CHECK:   - Type:            EXPORT
-; CHECK:     Exports:         
-; CHECK:       - Name:            a
-; CHECK:         Kind:            GLOBAL
-; CHECK:         Index:           2
-; CHECK:       - Name:            b
-; CHECK:         Kind:            GLOBAL
-; CHECK:         Index:           3
-; CHECK:   - Type:            DATA
-; CHECK:     Relocations:     
-; CHECK:       - Type:            R_WEBASSEMBLY_GLOBAL_ADDR_I32
-; CHECK:         Index:           0
-; CHECK:         Offset:          0x00000016
-; CHECK:       - Type:            R_WEBASSEMBLY_GLOBAL_ADDR_I32
-; CHECK:         Index:           1
-; CHECK:         Offset:          0x0000001E
-; CHECK:     Segments:        
-; CHECK:       - Index:           0
-; CHECK:         Offset:          
-; CHECK:           Opcode:          I32_CONST
-; CHECK:           Value:           0
-; CHECK:         Content:         68656C6C6F00776F726C640000000000000000000000000006000000
+; CHECK:        - Type:            GLOBAL
+; CHECK-NEXT:     Globals:         
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           0
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           6
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           16
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           24
+; CHECK-NEXT:   - Type:            EXPORT
+; CHECK-NEXT:     Exports:         
+; CHECK-NEXT:       - Name:            a
+; CHECK-NEXT:         Kind:            GLOBAL
+; CHECK-NEXT:         Index:           2
+; CHECK-NEXT:       - Name:            b
+; CHECK-NEXT:         Kind:            GLOBAL
+; CHECK-NEXT:         Index:           3
+; CHECK-NEXT:   - Type:            DATA
+; CHECK-NEXT:     Relocations:     
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_GLOBAL_ADDR_I32
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000016
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_GLOBAL_ADDR_I32
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:         Offset:          0x0000001E
+; CHECK-NEXT:     Segments:        
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           0
+; CHECK-NEXT:         Content:         68656C6C6F00776F726C640000000000000000000000000006000000
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        28
+; CHECK-NEXT:     DataAlignment:   8
+; CHECK-NEXT:     SymbolInfo:      
+; CHECK-NEXT: ...
diff --git a/llvm/test/MC/WebAssembly/weak-alias.ll b/llvm/test/MC/WebAssembly/weak-alias.ll
index 9e4cc4e..6e2b863 100644
--- a/llvm/test/MC/WebAssembly/weak-alias.ll
+++ b/llvm/test/MC/WebAssembly/weak-alias.ll
@@ -27,6 +27,8 @@
 ; CHECK-NEXT:         Name:            foo
 ; CHECK-NEXT:   - Type:            CUSTOM
 ; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        0
+; CHECK-NEXT:     DataAlignment:   0
 ; CHECK-NEXT:     SymbolInfo:      
 ; CHECK-NEXT:       - Name:            foo_alias
 ; CHECK-NEXT:         Flags:           1
diff --git a/llvm/test/MC/WebAssembly/weak.ll b/llvm/test/MC/WebAssembly/weak.ll
index 73d40af..1bc06fe 100644
--- a/llvm/test/MC/WebAssembly/weak.ll
+++ b/llvm/test/MC/WebAssembly/weak.ll
@@ -26,6 +26,8 @@
 ; CHECK-NEXT:         Name:            weak_function
 ; CHECK-NEXT:   - Type:            CUSTOM
 ; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        0
+; CHECK-NEXT:     DataAlignment:   0
 ; CHECK-NEXT:     SymbolInfo:      
 ; CHECK-NEXT:       - Name:            weak_external_data
 ; CHECK-NEXT:         Flags:           1
diff --git a/llvm/test/ObjectYAML/wasm/weak_symbols.yaml b/llvm/test/ObjectYAML/wasm/weak_symbols.yaml
index 0ae8c9b..ab80c1e 100644
--- a/llvm/test/ObjectYAML/wasm/weak_symbols.yaml
+++ b/llvm/test/ObjectYAML/wasm/weak_symbols.yaml
@@ -3,6 +3,19 @@
 FileHeader:
   Version:         0x00000001
 Sections:
+  - Type:            TYPE
+    Signatures:
+      - ReturnType:      I32
+        ParamTypes:
+  - Type:            FUNCTION
+    FunctionTypes:   [ 0, 0 ]
+  - Type:            GLOBAL
+    Globals:         
+      - Type:        I32
+        Mutable:     false
+        InitExpr:
+          Opcode:          I32_CONST
+          Value:           1
   - Type:            EXPORT
     Exports:         
       - Name:            function_export
@@ -10,9 +23,11 @@
         Index:           1
       - Name:            global_export
         Kind:            GLOBAL
-        Index:           2
+        Index:           0
   - Type:            CUSTOM
     Name:            linking
+    DataSize:        10
+    DataAlignment:   2
     SymbolInfo:
       - Name:            function_export
         Flags:           1
@@ -30,9 +45,11 @@
 # CHECK:         Index:           1
 # CHECK:       - Name:            global_export
 # CHECK:         Kind:            GLOBAL
-# CHECK:         Index:           2
+# CHECK:         Index:           0
 # CHECK:   - Type:            CUSTOM
 # CHECK:     Name:            linking
+# CHECK:     DataSize:        10
+# CHECK:     DataAlignment:   2
 # CHECK:     SymbolInfo:
 # CHECK:       - Name:            function_export
 # CHECK:         Flags:           1
diff --git a/llvm/test/tools/llvm-nm/wasm/weak-symbols.yaml b/llvm/test/tools/llvm-nm/wasm/weak-symbols.yaml
index 682a874..d46ca1a 100644
--- a/llvm/test/tools/llvm-nm/wasm/weak-symbols.yaml
+++ b/llvm/test/tools/llvm-nm/wasm/weak-symbols.yaml
@@ -33,6 +33,8 @@
         Index:           0x00000002
   - Type:            CUSTOM
     Name:            linking
+    DataSize:        0
+    DataAlignment:   2
     SymbolInfo:
       - Name:            weak_global_func
         Flags:           1
diff --git a/llvm/tools/obj2yaml/wasm2yaml.cpp b/llvm/tools/obj2yaml/wasm2yaml.cpp
index ad0075c..1df6afc 100644
--- a/llvm/tools/obj2yaml/wasm2yaml.cpp
+++ b/llvm/tools/obj2yaml/wasm2yaml.cpp
@@ -77,6 +77,8 @@
         LinkingSec->SymbolInfos.push_back(Info);
       }
     }
+    LinkingSec->DataSize = Obj.linkingData().DataSize;
+    LinkingSec->DataAlignment = Obj.linkingData().DataAlignment;
     CustomSec = std::move(LinkingSec);
   } else {
     CustomSec = make_unique<WasmYAML::CustomSection>(WasmSec.Name);
diff --git a/llvm/tools/yaml2obj/yaml2wasm.cpp b/llvm/tools/yaml2obj/yaml2wasm.cpp
index cf591e1..110700d 100644
--- a/llvm/tools/yaml2obj/yaml2wasm.cpp
+++ b/llvm/tools/yaml2obj/yaml2wasm.cpp
@@ -110,22 +110,52 @@
   return 0;
 }
 
-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);
+class SubSectionWriter {
+  raw_ostream &OS;
+  std::string OutString;
+  raw_string_ostream StringStream;
 
-    encodeULEB128(Section.SymbolInfos.size(), StringStream);
-    for (const WasmYAML::SymbolInfo &Info : Section.SymbolInfos) {
-      writeStringRef(Info.Name, StringStream);
-      encodeULEB128(Info.Flags, StringStream);
-    }
+public:
+  SubSectionWriter(raw_ostream &OS) : OS(OS), StringStream(OutString) {}
 
+  void Done() {
     StringStream.flush();
     encodeULEB128(OutString.size(), OS);
     OS << OutString;
+    OutString.clear();
+  }
+
+  raw_ostream& GetStream() {
+    return StringStream;
+  }
+};
+
+int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section) {
+  writeStringRef(Section.Name, OS);
+
+  SubSectionWriter SubSection(OS);
+
+  // DATA_SIZE subsection
+  encodeULEB128(wasm::WASM_DATA_SIZE, OS);
+  encodeULEB128(Section.DataSize, SubSection.GetStream());
+  SubSection.Done();
+
+  // DATA_ALIGNMENT subsection
+  encodeULEB128(wasm::WASM_DATA_ALIGNMENT, OS);
+  encodeULEB128(Section.DataAlignment, SubSection.GetStream());
+  SubSection.Done();
+
+  // SYMBOL_INFO subsection
+  if (Section.SymbolInfos.size()) {
+    encodeULEB128(wasm::WASM_SYMBOL_INFO, OS);
+
+    encodeULEB128(Section.SymbolInfos.size(), SubSection.GetStream());
+    for (const WasmYAML::SymbolInfo &Info : Section.SymbolInfos) {
+      writeStringRef(Info.Name, SubSection.GetStream());
+      encodeULEB128(Info.Flags, SubSection.GetStream());
+    }
+
+    SubSection.Done();
   }
   return 0;
 }
@@ -134,18 +164,16 @@
   writeStringRef(Section.Name, OS);
   if (Section.FunctionNames.size()) {
     encodeULEB128(wasm::WASM_NAMES_FUNCTION, OS);
-    std::string OutString;
-    raw_string_ostream StringStream(OutString);
 
-    encodeULEB128(Section.FunctionNames.size(), StringStream);
+    SubSectionWriter SubSection(OS);
+
+    encodeULEB128(Section.FunctionNames.size(), SubSection.GetStream());
     for (const WasmYAML::NameEntry &NameEntry : Section.FunctionNames) {
-      encodeULEB128(NameEntry.Index, StringStream);
-      writeStringRef(NameEntry.Name, StringStream);
+      encodeULEB128(NameEntry.Index, SubSection.GetStream());
+      writeStringRef(NameEntry.Name, SubSection.GetStream());
     }
 
-    StringStream.flush();
-    encodeULEB128(OutString.size(), OS);
-    OS << OutString;
+    SubSection.Done();
   }
   return 0;
 }