github.com/taubyte/vm-wasm-utils@v1.0.2/binary/section.go (about) 1 package binary 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 8 wasm "github.com/taubyte/vm-wasm-utils" 9 "github.com/taubyte/vm-wasm-utils/leb128" 10 ) 11 12 func decodeTypeSection(enabledFeatures wasm.Features, r *bytes.Reader) ([]*wasm.FunctionType, error) { 13 vs, _, err := leb128.DecodeUint32(r) 14 if err != nil { 15 return nil, fmt.Errorf("get size of vector: %w", err) 16 } 17 18 result := make([]*wasm.FunctionType, vs) 19 for i := uint32(0); i < vs; i++ { 20 if result[i], err = decodeFunctionType(enabledFeatures, r); err != nil { 21 return nil, fmt.Errorf("read %d-th type: %v", i, err) 22 } 23 } 24 return result, nil 25 } 26 27 func decodeImportSection( 28 r *bytes.Reader, 29 memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32), 30 enabledFeatures wasm.Features, 31 ) ([]*wasm.Import, error) { 32 vs, _, err := leb128.DecodeUint32(r) 33 if err != nil { 34 return nil, fmt.Errorf("get size of vector: %w", err) 35 } 36 37 result := make([]*wasm.Import, vs) 38 for i := uint32(0); i < vs; i++ { 39 if result[i], err = decodeImport(r, i, memorySizer, enabledFeatures); err != nil { 40 return nil, err 41 } 42 } 43 return result, nil 44 } 45 46 func decodeFunctionSection(r *bytes.Reader) ([]uint32, error) { 47 vs, _, err := leb128.DecodeUint32(r) 48 if err != nil { 49 return nil, fmt.Errorf("get size of vector: %w", err) 50 } 51 52 result := make([]uint32, vs) 53 for i := uint32(0); i < vs; i++ { 54 if result[i], _, err = leb128.DecodeUint32(r); err != nil { 55 return nil, fmt.Errorf("get type index: %w", err) 56 } 57 } 58 return result, err 59 } 60 61 func decodeTableSection(r *bytes.Reader, enabledFeatures wasm.Features) ([]*wasm.Table, error) { 62 vs, _, err := leb128.DecodeUint32(r) 63 if err != nil { 64 return nil, fmt.Errorf("error reading size") 65 } 66 if vs > 1 { 67 if err := enabledFeatures.Require(wasm.FeatureReferenceTypes); err != nil { 68 return nil, fmt.Errorf("at most one table allowed in module as %w", err) 69 } 70 } 71 72 ret := make([]*wasm.Table, vs) 73 for i := range ret { 74 table, err := decodeTable(r, enabledFeatures) 75 if err != nil { 76 return nil, err 77 } 78 ret[i] = table 79 } 80 return ret, nil 81 } 82 83 func decodeMemorySection( 84 r *bytes.Reader, 85 memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32), 86 ) (*wasm.Memory, error) { 87 vs, _, err := leb128.DecodeUint32(r) 88 if err != nil { 89 return nil, fmt.Errorf("error reading size") 90 } 91 if vs > 1 { 92 return nil, fmt.Errorf("at most one memory allowed in module, but read %d", vs) 93 } 94 95 return decodeMemory(r, memorySizer) 96 } 97 98 func decodeGlobalSection(r *bytes.Reader, enabledFeatures wasm.Features) ([]*wasm.Global, error) { 99 vs, _, err := leb128.DecodeUint32(r) 100 if err != nil { 101 return nil, fmt.Errorf("get size of vector: %w", err) 102 } 103 104 result := make([]*wasm.Global, vs) 105 for i := uint32(0); i < vs; i++ { 106 if result[i], err = decodeGlobal(r, enabledFeatures); err != nil { 107 return nil, fmt.Errorf("global[%d]: %w", i, err) 108 } 109 } 110 return result, nil 111 } 112 113 func decodeExportSection(r *bytes.Reader) ([]*wasm.Export, error) { 114 vs, _, sizeErr := leb128.DecodeUint32(r) 115 if sizeErr != nil { 116 return nil, fmt.Errorf("get size of vector: %v", sizeErr) 117 } 118 119 usedName := make(map[string]struct{}, vs) 120 exportSection := make([]*wasm.Export, 0, vs) 121 for i := wasm.Index(0); i < vs; i++ { 122 export, err := decodeExport(r) 123 if err != nil { 124 return nil, fmt.Errorf("read export: %w", err) 125 } 126 if _, ok := usedName[export.Name]; ok { 127 return nil, fmt.Errorf("export[%d] duplicates name %q", i, export.Name) 128 } else { 129 usedName[export.Name] = struct{}{} 130 } 131 exportSection = append(exportSection, export) 132 } 133 return exportSection, nil 134 } 135 136 func decodeStartSection(r *bytes.Reader) (*wasm.Index, error) { 137 vs, _, err := leb128.DecodeUint32(r) 138 if err != nil { 139 return nil, fmt.Errorf("get function index: %w", err) 140 } 141 return &vs, nil 142 } 143 144 func decodeElementSection(r *bytes.Reader, enabledFeatures wasm.Features) ([]*wasm.ElementSegment, error) { 145 vs, _, err := leb128.DecodeUint32(r) 146 if err != nil { 147 return nil, fmt.Errorf("get size of vector: %w", err) 148 } 149 150 result := make([]*wasm.ElementSegment, vs) 151 for i := uint32(0); i < vs; i++ { 152 if result[i], err = decodeElementSegment(r, enabledFeatures); err != nil { 153 return nil, fmt.Errorf("read element: %w", err) 154 } 155 } 156 return result, nil 157 } 158 159 func decodeCodeSection(r *bytes.Reader) ([]*wasm.Code, error) { 160 vs, _, err := leb128.DecodeUint32(r) 161 if err != nil { 162 return nil, fmt.Errorf("get size of vector: %w", err) 163 } 164 165 result := make([]*wasm.Code, vs) 166 for i := uint32(0); i < vs; i++ { 167 if result[i], err = decodeCode(r); err != nil { 168 return nil, fmt.Errorf("read %d-th code segment: %v", i, err) 169 } 170 } 171 return result, nil 172 } 173 174 func decodeDataSection(r *bytes.Reader, enabledFeatures wasm.Features) ([]*wasm.DataSegment, error) { 175 vs, _, err := leb128.DecodeUint32(r) 176 if err != nil { 177 return nil, fmt.Errorf("get size of vector: %w", err) 178 } 179 180 result := make([]*wasm.DataSegment, vs) 181 for i := uint32(0); i < vs; i++ { 182 if result[i], err = decodeDataSegment(r, enabledFeatures); err != nil { 183 return nil, fmt.Errorf("read data segment: %w", err) 184 } 185 } 186 return result, nil 187 } 188 189 func decodeDataCountSection(r *bytes.Reader) (count *uint32, err error) { 190 v, _, err := leb128.DecodeUint32(r) 191 if err != nil && err != io.EOF { 192 // data count is optional, so EOF is fine. 193 return nil, err 194 } 195 return &v, nil 196 } 197 198 // encodeSection encodes the sectionID, the size of its contents in bytes, followed by the contents. 199 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0 200 func encodeSection(sectionID wasm.SectionID, contents []byte) []byte { 201 return append([]byte{sectionID}, encodeSizePrefixed(contents)...) 202 } 203 204 // encodeTypeSection encodes a wasm.SectionIDType for the given imports in WebAssembly 1.0 (20191205) Binary 205 // Format. 206 // 207 // See encodeFunctionType 208 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#type-section%E2%91%A0 209 func encodeTypeSection(types []*wasm.FunctionType) []byte { 210 contents := leb128.EncodeUint32(uint32(len(types))) 211 for _, t := range types { 212 contents = append(contents, encodeFunctionType(t)...) 213 } 214 return encodeSection(wasm.SectionIDType, contents) 215 } 216 217 // encodeImportSection encodes a wasm.SectionIDImport for the given imports in WebAssembly 1.0 (20191205) Binary 218 // Format. 219 // 220 // See encodeImport 221 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#import-section%E2%91%A0 222 func encodeImportSection(imports []*wasm.Import) []byte { 223 contents := leb128.EncodeUint32(uint32(len(imports))) 224 for _, i := range imports { 225 contents = append(contents, encodeImport(i)...) 226 } 227 return encodeSection(wasm.SectionIDImport, contents) 228 } 229 230 // encodeFunctionSection encodes a wasm.SectionIDFunction for the type indices associated with module-defined 231 // functions in WebAssembly 1.0 (20191205) Binary Format. 232 // 233 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-section%E2%91%A0 234 func encodeFunctionSection(typeIndices []wasm.Index) []byte { 235 contents := leb128.EncodeUint32(uint32(len(typeIndices))) 236 for _, index := range typeIndices { 237 contents = append(contents, leb128.EncodeUint32(index)...) 238 } 239 return encodeSection(wasm.SectionIDFunction, contents) 240 } 241 242 // encodeCodeSection encodes a wasm.SectionIDCode for the module-defined function in WebAssembly 1.0 (20191205) 243 // Binary Format. 244 // 245 // See encodeCode 246 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0 247 func encodeCodeSection(code []*wasm.Code) []byte { 248 contents := leb128.EncodeUint32(uint32(len(code))) 249 for _, i := range code { 250 contents = append(contents, encodeCode(i)...) 251 } 252 return encodeSection(wasm.SectionIDCode, contents) 253 } 254 255 // encodeTableSection encodes a wasm.SectionIDTable for the module-defined function in WebAssembly 1.0 256 // (20191205) Binary Format. 257 // 258 // See encodeTable 259 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-section%E2%91%A0 260 func encodeTableSection(tables []*wasm.Table) []byte { 261 var contents []byte = leb128.EncodeUint32(uint32(len(tables))) 262 for _, table := range tables { 263 contents = append(contents, encodeTable(table)...) 264 } 265 return encodeSection(wasm.SectionIDTable, contents) 266 } 267 268 // encodeMemorySection encodes a wasm.SectionIDMemory for the module-defined function in WebAssembly 1.0 269 // (20191205) Binary Format. 270 // 271 // See encodeMemory 272 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0 273 func encodeMemorySection(memory *wasm.Memory) []byte { 274 contents := append([]byte{1}, encodeMemory(memory)...) 275 return encodeSection(wasm.SectionIDMemory, contents) 276 } 277 278 // encodeGlobalSection encodes a wasm.SectionIDGlobal for the given globals in WebAssembly 1.0 (20191205) Binary 279 // Format. 280 // 281 // See encodeGlobal 282 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-section%E2%91%A0 283 func encodeGlobalSection(globals []*wasm.Global) []byte { 284 contents := leb128.EncodeUint32(uint32(len(globals))) 285 for _, g := range globals { 286 contents = append(contents, encodeGlobal(g)...) 287 } 288 return encodeSection(wasm.SectionIDGlobal, contents) 289 } 290 291 // encodeExportSection encodes a wasm.SectionIDExport for the given exports in WebAssembly 1.0 (20191205) Binary 292 // Format. 293 // 294 // See encodeExport 295 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#export-section%E2%91%A0 296 func encodeExportSection(exports []*wasm.Export) []byte { 297 contents := leb128.EncodeUint32(uint32(len(exports))) 298 for _, e := range exports { 299 contents = append(contents, encodeExport(e)...) 300 } 301 return encodeSection(wasm.SectionIDExport, contents) 302 } 303 304 // encodeStartSection encodes a wasm.SectionIDStart for the given function index in WebAssembly 1.0 (20191205) 305 // Binary Format. 306 // 307 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-section%E2%91%A0 308 func encodeStartSection(funcidx wasm.Index) []byte { 309 return encodeSection(wasm.SectionIDStart, leb128.EncodeUint32(funcidx)) 310 } 311 312 // encodeEelementSection encodes a wasm.SectionIDElement for the elements in WebAssembly 1.0 (20191205) 313 // Binary Format. 314 // 315 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#element-section%E2%91%A0 316 func encodeElementSection(elements []*wasm.ElementSegment) []byte { 317 contents := leb128.EncodeUint32(uint32(len(elements))) 318 for _, e := range elements { 319 contents = append(contents, encodeElement(e)...) 320 } 321 return encodeSection(wasm.SectionIDElement, contents) 322 } 323 324 // encodeDataSection encodes a wasm.SectionIDData for the data in WebAssembly 1.0 (20191205) 325 // Binary Format. 326 // 327 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#data-section%E2%91%A0 328 func encodeDataSection(datum []*wasm.DataSegment) []byte { 329 contents := leb128.EncodeUint32(uint32(len(datum))) 330 for _, d := range datum { 331 contents = append(contents, encodeDataSegment(d)...) 332 } 333 return encodeSection(wasm.SectionIDData, contents) 334 }