From: Mike Lowis Date: Thu, 2 Nov 2023 16:14:27 +0000 (-0400) Subject: dynamic generation of syscall stubs X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=8fa3a3e28de24463788b960ca19e4bed21b976a5;p=proto%2Faas.git dynamic generation of syscall stubs --- diff --git a/aas.rb b/aas.rb index 9ab41c2..c0a4a87 100755 --- 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 + diff --git a/example.s b/example.s index 0b22220..c6a6227 100644 --- 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