From: Mike Lowis Date: Mon, 30 Oct 2023 17:07:25 +0000 (-0400) Subject: initial commit. Able to generate assembly and a functioning executable X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=ee18bcccba6613eb5da66484e9a248db6ec7a183;p=proto%2Faas.git initial commit. Able to generate assembly and a functioning executable --- ee18bcccba6613eb5da66484e9a248db6ec7a183 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d7756c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +a.out +*.o diff --git a/aas.rb b/aas.rb new file mode 100755 index 0000000..9ab41c2 --- /dev/null +++ b/aas.rb @@ -0,0 +1,415 @@ +#!/bin/env ruby + +require "tempfile" + +def emit(text) + $asm_out.write "\t#{text}\n" +end + + +module Targets + module X86_64 + class << self + def int(value) + # TODO: optimize this based on size of operand + emit "mov $#{value}, %rax" + emit "pushq %rax" + end + + ############# + # ARITHMETIC + ############# + # negi + def negi + emit "negq (%rsp)" + end + + def addi + emit "popq %rax" + emit "addq %rax, (%rsp)" + end + + def subi + emit "popq %rax" + emit "subq %rax, (%rsp)" + end + + def muli + emit "popq %rax" + emit "popq %rbx" + emit "imull %rbx, %rax" + emit "pushq %rax" + end + + def divi + emit "popq %rax" + emit "popq %rbx" + emit "idivl %rbx, %rax" + emit "pushq %rax" + end + + def modi + emit "popq %rax" + emit "popq %rbx" + emit "idivl %rbx, %rax" + emit "pushq %rdx" + end + + def inci + emit "incq (%rsp)" + end + + def deci + emit "decq (%rsp)" + end + + # negf + # addf + # subf + # divf + # mulf + # modf !LIBRARY! + # incf + # decf + + ############# + # RELATIONAL + ############# + # eqi + def eqi + emit "popq %rax" + emit "popq %rbx" + emit "cmpq %rbx, %rax" + emit "sete %al" + emit "movzbq %al, %rax" + emit "pushq %rax" + end + + # nei + def nei + emit "popq %rax" + emit "popq %rbx" + emit "cmpq %rbx, %rax" + emit "setne %al" + emit "movzbq %al, %rax" + emit "pushq %rax" + end + + # lti + def lti + emit "popq %rax" + emit "popq %rbx" + emit "cmpq %rbx, %rax" + emit "setl %al" + emit "movzbq %al, %rax" + emit "pushq %rax" + end + + # gti + def gti + emit "popq %rax" + emit "popq %rbx" + emit "cmpq %rbx, %rax" + emit "setg %al" + emit "movzbq %al, %rax" + emit "pushq %rax" + end + + # ltei + def ltei + emit "popq %rax" + emit "popq %rbx" + emit "cmpq %rbx, %rax" + emit "setle %al" + emit "movzbq %al, %rax" + emit "pushq %rax" + end + + # gtei + def gtei + emit "popq %rax" + emit "popq %rbx" + emit "cmpq %rbx, %rax" + emit "setge %al" + emit "movzbq %al, %rax" + emit "pushq %rax" + end + + # eqf + # nef + # ltf + # gtf + # ltef + # gtef + + ########## + # LOGICAL + ########## + def andi + emit "popq %rax" + emit "andq %rax, (%rsp)" + end + + def ori + emit "popq %rax" + emit "orq %rax, (%rsp)" + end + + def noti + emit "notq (%rsp)" + end + + ########## + # BITWISE + ########## + # bit_and + def bit_and + emit "popq %rax" + emit "andq %rax, (%rsp)" + end + + # bit_or + def bit_or + emit "popq %rax" + emit "orq %rax, (%rsp)" + end + + # bit_xor + def bit_xor + emit "popq %rax" + emit "orq %rax, (%rsp)" + end + + # bit_not + def bit_not + emit "notq (%rsp)" + end + + # bit_asl + def bit_asl + emit "popq %rax" + emit "popq %rbx" + emit "salq %bl, %rax" + emit "popq %rax" + end + + # bit_asr + def bit_asl + emit "popq %rax" + emit "popq %rbx" + emit "sharq %bl, %rax" + emit "popq %rax" + end + + # bit_lsr + def bit_ + emit "popq %rax" + emit "popq %rbx" + emit "shrq %bl, %rax" + emit "popq %rax" + end + + ############ + # FUNCTIONS + ############ + # call NA + def call + emit "call #{name}" + end + + # call_and_ret + def call_and_ret + emit "call #{name}" + emit "pushq %rax" + end + +# def ret +# end +# +# def ret_with_val +# end + + def syscall num_args + emit "call syscall#{num_args}" + end + + ######### + # MEMORY + ######### + # get_global int + # set_global int + # get_local int + # set_local int + end + end +end + +class Variable + def initialize(name, &block) + $asm_out.write ".data\n" + $asm_out.write "#{name}:\n" + instance_eval(&block) + $asm_out.write "\n" + end + + def int(value) + emit ".long #{value.to_i}" + end + + def float(value) + emit ".long #{value.to_i}" + emit ".long #{value.to_i}" + end + + def bool(value) + emit ".byte #{value ? 1 : 0}" + end + + def byte(value) + emit ".byte 0x#{"%02x" % value.to_i}" + end + + private + + def emit(text) + $asm_out.write "\t#{text}\n" + end + +end + +class Function + def initialize(name, args=[], returns = nil, &block) + $asm_out.write ".text\n" + $asm_out.write "#{name}:\n" + emit "pushq %rbp" + emit "movq %rsp, %rbp" +# emit ";-------------------" + instance_eval(&block) +# emit ";-------------------" + emit "popq %rax" if returns + emit "popq %rbp" + emit "ret" + $asm_out.write "\n" + end + + def method_missing(m, *args, &block) + $target::send(m, *args, &block) + end + + ## + # Function Scaffolding: Locals and Returns + ## + + def locals(count) + $asm_out.write "subq $#{count * 8}, %rsp\n" + end + + +# ## +# # Literal Value Loading +# ## +# +# def int(value) +# puts "\tmovq\t$#{value}, %rax" +# puts "\tpushq\t%rax" +# end +# +# def float(value) +## puts "\tmovq\t$#{value}, %rax" +## puts "\tpushq\t%rax" +# end +# +# def bool(value) +# puts "\tmovq\t$#{value}, %rax" +# puts "\tpushq\t%rax" +# end +# +# def byte(value) +# puts "\tmovq\t$#{value}, %rax" +# puts "\tpushq\t%rax" +# end + + +# ## +# # Local/Global Variable Access +# ## +# +# def local_get(idx) +# raise "unimplemented" +# end +# +# def local_set(idx) +# raise "unimplemented" +# end +# +# def global_get(idx) +# raise "unimplemented" +# end +# +# def global_set(idx) +# raise "unimplemented" +# end +# +# def ret() +# puts "\tret" +# end +# +# def ret_val() +# puts "\tret" +# end + + + def var(name, &block) + raise "variable declarations not allowed inside function block" + end + + def func(name, args=[], &block) + raise "nested functions are disallowed" + end + + def target(name) + raise "target output can only be specified at the top level" + end +end + +#def label(name, &block) +# puts "name:" +# block.call() +#end + +def prog_start func + $asm_out.write ".text\n" + $asm_out.write ".global _start\n" + $asm_out.write "_start:\n" + emit "movl (%rsp), %edi\n" + emit "lea 8(%rsp), %rsi\n" + emit "call #{func || main}\n" + emit "movl %eax, %edi\n" + emit "movl $60, %eax\n" + emit "syscall\n" + $asm_out.write "" +end + +def var(name, &block) + Variable.new(name, &block) +end + +def func(name, args=[], returns = nil, &block) + Function.new(name, args, returns, &block) +end + +def target(name) + $target = Targets.const_get(name.to_s) +end + +# Process all the files +$target = Targets::X86_64 +$out_name = ARGV[0] +$asm_out = Tempfile.new("aas") +ARGV[1..-1].each do |f| + puts "loading #{f}" + load f +end +$asm_out.close +#puts File.read($asm_out.path) +system "as -o #{$out_name} #{$asm_out.path}" diff --git a/example.s b/example.s new file mode 100644 index 0000000..0b22220 --- /dev/null +++ b/example.s @@ -0,0 +1,15 @@ +prog_start :bar + +var :foo do + int 42 + float 42.0 + bool false + byte 0x42 +end + +func :bar, [], :int do +# locals 2 + int 4 + int 2 + addi +end \ No newline at end of file