]> git.mdlowis.com Git - proto/aas.git/commitdiff
dynamic generation of syscall stubs
authorMike Lowis <mike.lowis@gentex.com>
Thu, 2 Nov 2023 16:14:27 +0000 (12:14 -0400)
committerMike Lowis <mike.lowis@gentex.com>
Thu, 2 Nov 2023 16:14:27 +0000 (12:14 -0400)
aas.rb
example.s

diff --git a/aas.rb b/aas.rb
index 9ab41c21e4a53386c9566094e4199965fb1d1767..c0a4a87f933ea5ba0df90cb226657666b6c46ec8 100755 (executable)
--- a/aas.rb
+++ b/aas.rb
@@ -3,9 +3,21 @@
 require "tempfile"
 
 def emit(text)
-  $asm_out.write "\t#{text}\n"
+  $asm_out.write "    #{text}\n"
 end
 
+START_CODE = <<-eos
+.text
+.global _start
+_start:
+    movl      (%rsp), %edi
+    lea       8(%rsp), %rsi
+    call      main
+    movl      %eax, %edi
+    movl      $60, %eax
+    syscall
+
+eos
 
 module Targets
   module X86_64
@@ -212,25 +224,19 @@ module Targets
       ############
       # 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
+      def scall num_args
+        $syscalls[num_args] = true
         emit "call      syscall#{num_args}"
+        emit "pushq     %rax"
       end
 
       #########
@@ -268,28 +274,19 @@ class Variable
   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)
+  def initialize(name, nargs = 0, &block)
+    @nargs = nargs
+    @returned = false
     $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"
+    raise "functions require at least one return instruction" if not @returned
   end
 
   def method_missing(m, *args, &block)
@@ -304,60 +301,20 @@ class Function
     $asm_out.write "subq     $#{count * 8}, %rsp\n"
   end
 
+  def ret
+    emit "popq      %rbp"
+    if @nargs > 0 then
+      emit "ret       $#{@nargs * 8}"
+    else
+      emit "ret"
+    end
+    @returned = true
+  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 retwv
+    emit "popq      %rax"
+    ret
+  end
 
   def var(name, &block)
     raise "variable declarations not allowed inside function block"
@@ -372,44 +329,52 @@ class Function
   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)
+def func(name, nargs=0, &block)
+  Function.new(name, nargs, &block)
+  $main_obj = true if name == :main
 end
 
 def target(name)
   $target = Targets.const_get(name.to_s)
 end
 
-# Process all the files
+def gen_syscall_handler(n)
+  regs = %w[%rdi %rsi %rdx %r10 %r8 %r9]
+  $asm_out.write ".text\n"
+  $asm_out.write ".global syscall#{n}\n"
+  $asm_out.write "syscall#{n}:\n"
+  emit "movq      8(%rsp), %rax"
+  n.times do |i|
+    emit "movq      #{(n+1)*8}(%rsp), #{regs[i]}"
+  end
+  emit "syscall"
+  emit "ret     $#{(n+1) * 8}"
+  $asm_out.write "\n"
+end
+
+# Setup assembler global state
+$main_obj = false
+$syscalls = [false, false, false, false, false, false, false]
 $target   = Targets::X86_64
 $out_name = ARGV[0]
 $asm_out  = Tempfile.new("aas")
+
+# Process all the input files
 ARGV[1..-1].each do |f|
-  puts "loading #{f}"
   load f
 end
+$syscalls.each_with_index do |used, n|
+  gen_syscall_handler(n) if used
+end
+$asm_out.write START_CODE if $main_obj
+
+# Now run it through the system assembler
 $asm_out.close
-#puts File.read($asm_out.path)
+puts File.read($asm_out.path)
 system "as -o #{$out_name} #{$asm_out.path}"
+$asm_out.unlink
+
index 0b22220ff44d04ac48009d2e4c2a3a436fca6c39..c6a6227cf2c992f707622d4e4e2361232ec05254 100644 (file)
--- a/example.s
+++ b/example.s
@@ -1,15 +1,14 @@
-prog_start :bar
+#var :foo do
+#  int 42
+#  float 42.0
+#  bool false
+#  byte 0x42
+#end
 
-var :foo do
-  int 42
-  float 42.0
-  bool false
-  byte 0x42
-end
-
-func :bar, [], :int do
+func :main do
 #  locals 2
-  int 4
-  int 2
-  addi
+  int 0
+  int 3
+  scall 1
+  retwv
 end
\ No newline at end of file