|
require "./encoding" |
|
include Encoding |
|
|
|
# https://webassembly.github.io/spec/core/binary/modules.html#sections |
|
enum Section : UInt8 |
|
Custom |
|
Type |
|
Import |
|
Func |
|
Table |
|
Memory |
|
Global |
|
Export |
|
Start |
|
Element |
|
Code |
|
Data |
|
end |
|
|
|
# https://webassembly.github.io/spec/core/binary/types.html |
|
module Valtype |
|
I32 = 0x7f |
|
I64 = 0x7e |
|
F32 = 0x7d |
|
end |
|
|
|
|
|
# https://webassembly.github.io/spec/core/binary/instructions.html |
|
module Opcodes |
|
End = 0x0b |
|
GetLocal = 0x20 |
|
F32Add = 0x92 |
|
end |
|
|
|
# http://webassembly.github.io/spec/core/binary/modules.html#export-section |
|
module ExportType |
|
Func = 0x00 |
|
Table = 0x01 |
|
Mem = 0x02 |
|
Global = 0x03 |
|
end |
|
|
|
# http://webassembly.github.io/spec/core/binary/types.html#function-types |
|
FunctionType = 0x60 |
|
|
|
EmptyArray = 0x0 |
|
|
|
|
|
# https://webassembly.github.io/spec/core/binary/conventions.html#binary-vec |
|
def encode_vector(data) : Array(UInt8) |
|
size = [data.size.to_u8] of UInt8 |
|
size + data.flatten.map(&.to_u8) |
|
end |
|
|
|
# https://webassembly.github.io/spec/core/binary/modules.html#sections |
|
def create_section(type : Section, data) : Array(UInt8) |
|
type = [type.value] of UInt8 |
|
type + encode_vector(data) |
|
end |
|
|
|
|
|
magic_module_header = [0x00, 0x61, 0x73, 0x6d] of UInt8 |
|
module_version = [0x01, 0x00, 0x00, 0x00] of UInt8 |
|
header = magic_module_header + module_version |
|
|
|
add_function_type = [FunctionType] + encode_vector([Valtype::F32, Valtype::F32]) + encode_vector([Valtype::F32]) |
|
type_section = create_section(Section::Type, encode_vector([add_function_type])) |
|
func_section = create_section(Section::Func, encode_vector([0x00])) |
|
export_section = create_section(Section::Export, encode_vector([encode_string("add") + [ExportType::Func, 0x00]])) |
|
|
|
code = [ |
|
Opcodes::GetLocal, |
|
unsigned_LEB128(0), |
|
Opcodes::GetLocal, |
|
unsigned_LEB128(1), |
|
Opcodes::F32Add |
|
].flatten |
|
|
|
function_body = encode_vector([ |
|
EmptyArray, |
|
code, |
|
Opcodes::End |
|
].flatten) |
|
|
|
code_section = create_section(Section::Code, encode_vector([function_body])) |
|
|
|
buffer = (header + type_section + func_section + export_section + code_section) |
|
|
|
File.open("crystal.wasm", "wb") do |f| |
|
ptr = (buffer.to_unsafe.as(UInt8*)) |
|
f.write(ptr.to_slice(buffer.size * sizeof(UInt8))) |
|
end |