voodoo 1.0.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/voodooc +85 -49
 - data/lib/voodoo.rb +11 -6
 - data/lib/voodoo/code_generator.rb +6 -6
 - data/lib/voodoo/compiler.rb +2 -2
 - data/lib/voodoo/config.rb +3 -3
 - data/lib/voodoo/generators/amd64_nasm_generator.rb +196 -118
 - data/lib/voodoo/generators/arm_gas_generator.rb +367 -334
 - data/lib/voodoo/generators/common_code_generator.rb +467 -69
 - data/lib/voodoo/generators/dummy_generator.rb +10 -0
 - data/lib/voodoo/generators/i386_nasm_generator.rb +93 -60
 - data/lib/voodoo/generators/mips_gas_generator.rb +275 -265
 - data/lib/voodoo/generators/nasm_generator.rb +253 -251
 - data/lib/voodoo/parser.rb +46 -22
 - data/lib/voodoo/validator.rb +118 -60
 - metadata +14 -14
 - data/lib/voodoo/generators/arm_gas_generator.rb~ +0 -957
 
    
        data/bin/voodooc
    CHANGED
    
    | 
         @@ -3,9 +3,10 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require 'getoptlong'
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            require 'voodoo'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'voodoo/generators/dummy_generator'
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
      
 8 
     | 
    
         
            +
            USAGE="USAGE: voodooc [options] <input file>"
         
     | 
| 
      
 9 
     | 
    
         
            +
            HELP=<<EOT
         
     | 
| 
       9 
10 
     | 
    
         
             
            Input file denotes the file to compile. The special name '-' causes
         
     | 
| 
       10 
11 
     | 
    
         
             
            voodooc to read from standard input. In that case, the -o option is
         
     | 
| 
       11 
12 
     | 
    
         
             
            mandatory.
         
     | 
| 
         @@ -18,6 +19,10 @@ Valid options are: 
     | 
|
| 
       18 
19 
     | 
    
         
             
                    Select target architecture. Use -a help to get a list of
         
     | 
| 
       19 
20 
     | 
    
         
             
                    supported architectures.
         
     | 
| 
       20 
21 
     | 
    
         | 
| 
      
 22 
     | 
    
         
            +
            -c
         
     | 
| 
      
 23 
     | 
    
         
            +
            --check
         
     | 
| 
      
 24 
     | 
    
         
            +
                    Check program for correctness, but do not actually compile it.
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
       21 
26 
     | 
    
         
             
            -f <format>
         
     | 
| 
       22 
27 
     | 
    
         
             
            --format <format>
         
     | 
| 
       23 
28 
     | 
    
         
             
            --output-format <format>
         
     | 
| 
         @@ -25,7 +30,7 @@ Valid options are: 
     | 
|
| 
       25 
30 
     | 
    
         
             
                    supported output formats for architecture.
         
     | 
| 
       26 
31 
     | 
    
         | 
| 
       27 
32 
     | 
    
         
             
            --features
         
     | 
| 
       28 
     | 
    
         
            -
                     
     | 
| 
      
 33 
     | 
    
         
            +
                    List the features supported by this implementation. The features
         
     | 
| 
       29 
34 
     | 
    
         
             
                    are listed in the format <feature name><tab><version>, ordered
         
     | 
| 
       30 
35 
     | 
    
         
             
                    by feature name. The program exits after printing the list of
         
     | 
| 
       31 
36 
     | 
    
         
             
                    features; no compilation is performed.
         
     | 
| 
         @@ -44,21 +49,67 @@ Valid options are: 
     | 
|
| 
       44 
49 
     | 
    
         
             
                    Display version information and exit. No compilation will be performed.
         
     | 
| 
       45 
50 
     | 
    
         
             
            EOT
         
     | 
| 
       46 
51 
     | 
    
         | 
| 
      
 52 
     | 
    
         
            +
            architecture = Voodoo::Config.default_architecture
         
     | 
| 
      
 53 
     | 
    
         
            +
            check_only = false
         
     | 
| 
       47 
54 
     | 
    
         
             
            input_file = nil
         
     | 
| 
       48 
55 
     | 
    
         
             
            output_file = nil
         
     | 
| 
       49 
     | 
    
         
            -
            architecture = Voodoo::Config.default_architecture
         
     | 
| 
       50 
56 
     | 
    
         
             
            output_format = Voodoo::Config.default_format
         
     | 
| 
       51 
57 
     | 
    
         
             
            show_features = false
         
     | 
| 
       52 
58 
     | 
    
         | 
| 
      
 59 
     | 
    
         
            +
            # Gets the input file name from the command line.
         
     | 
| 
      
 60 
     | 
    
         
            +
            def get_input_file_name
         
     | 
| 
      
 61 
     | 
    
         
            +
              if ARGV.length == 1
         
     | 
| 
      
 62 
     | 
    
         
            +
                input_file = ARGV[0]
         
     | 
| 
      
 63 
     | 
    
         
            +
              else
         
     | 
| 
      
 64 
     | 
    
         
            +
                if ARGV.length < 1
         
     | 
| 
      
 65 
     | 
    
         
            +
                  $stderr.puts "no input files"
         
     | 
| 
      
 66 
     | 
    
         
            +
                else
         
     | 
| 
      
 67 
     | 
    
         
            +
                  $stderr.puts "Too many arguments"
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
                $stderr.puts USAGE
         
     | 
| 
      
 70 
     | 
    
         
            +
                exit 0x80
         
     | 
| 
      
 71 
     | 
    
         
            +
              end
         
     | 
| 
      
 72 
     | 
    
         
            +
              input_file
         
     | 
| 
      
 73 
     | 
    
         
            +
            end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
            # If error is a Voodoo::Compiler::Error, prints error messages.
         
     | 
| 
      
 76 
     | 
    
         
            +
            # Else, re-raises error.
         
     | 
| 
      
 77 
     | 
    
         
            +
            def handle_error error
         
     | 
| 
      
 78 
     | 
    
         
            +
              # If error is a compiler error, iterate over all child errors and
         
     | 
| 
      
 79 
     | 
    
         
            +
              # print user-friendly messages. Else, re-raise so that the default
         
     | 
| 
      
 80 
     | 
    
         
            +
              # handling is performed.
         
     | 
| 
      
 81 
     | 
    
         
            +
              if error.kind_of? Voodoo::Compiler::Error
         
     | 
| 
      
 82 
     | 
    
         
            +
                error.errors.each do |e|
         
     | 
| 
      
 83 
     | 
    
         
            +
                  message = ''
         
     | 
| 
      
 84 
     | 
    
         
            +
                  if e.start_line != nil
         
     | 
| 
      
 85 
     | 
    
         
            +
                    message << "#{e.start_line}: "
         
     | 
| 
      
 86 
     | 
    
         
            +
                    if e.input_name != nil
         
     | 
| 
      
 87 
     | 
    
         
            +
                      message = "#{e.input_name}:#{message}"
         
     | 
| 
      
 88 
     | 
    
         
            +
                    else
         
     | 
| 
      
 89 
     | 
    
         
            +
                      message = "line #{message}"
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
                  end
         
     | 
| 
      
 92 
     | 
    
         
            +
                  message << e.message
         
     | 
| 
      
 93 
     | 
    
         
            +
                  $stderr.puts message
         
     | 
| 
      
 94 
     | 
    
         
            +
                  if e.text != nil
         
     | 
| 
      
 95 
     | 
    
         
            +
                    $stderr.print "\n  #{e.text.gsub("\n", "\n  ")}\n"
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
              else
         
     | 
| 
      
 99 
     | 
    
         
            +
                raise error
         
     | 
| 
      
 100 
     | 
    
         
            +
              end
         
     | 
| 
      
 101 
     | 
    
         
            +
            end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
       53 
103 
     | 
    
         
             
            #
         
     | 
| 
       54 
104 
     | 
    
         
             
            # Process command line
         
     | 
| 
       55 
105 
     | 
    
         
             
            #
         
     | 
| 
       56 
106 
     | 
    
         | 
| 
       57 
107 
     | 
    
         
             
            opts = GetoptLong.new(
         
     | 
| 
       58 
     | 
    
         
            -
              ['-- 
     | 
| 
       59 
     | 
    
         
            -
              ['-- 
     | 
| 
      
 108 
     | 
    
         
            +
              ['--arch', '--architecture', '-a', GetoptLong::REQUIRED_ARGUMENT],
         
     | 
| 
      
 109 
     | 
    
         
            +
              ['--check', '-c', GetoptLong::NO_ARGUMENT],
         
     | 
| 
       60 
110 
     | 
    
         
             
              ['--features', GetoptLong::NO_ARGUMENT],
         
     | 
| 
       61 
     | 
    
         
            -
              ['-- 
     | 
| 
      
 111 
     | 
    
         
            +
              ['--help', '-h', GetoptLong::NO_ARGUMENT],
         
     | 
| 
      
 112 
     | 
    
         
            +
              ['--output-file', '--output', '-o', GetoptLong::REQUIRED_ARGUMENT],
         
     | 
| 
       62 
113 
     | 
    
         
             
              ['--output-format', '--format', '-f', GetoptLong::REQUIRED_ARGUMENT ],
         
     | 
| 
       63 
114 
     | 
    
         
             
              ['--version', GetoptLong::NO_ARGUMENT]
         
     | 
| 
       64 
115 
     | 
    
         
             
            )
         
     | 
| 
         @@ -66,14 +117,16 @@ opts = GetoptLong.new( 
     | 
|
| 
       66 
117 
     | 
    
         
             
            # Process options
         
     | 
| 
       67 
118 
     | 
    
         
             
            opts.each do |opt, arg|
         
     | 
| 
       68 
119 
     | 
    
         
             
              case opt
         
     | 
| 
       69 
     | 
    
         
            -
              when '--help'
         
     | 
| 
       70 
     | 
    
         
            -
                puts usage
         
     | 
| 
       71 
     | 
    
         
            -
                puts help
         
     | 
| 
       72 
     | 
    
         
            -
                exit
         
     | 
| 
       73 
120 
     | 
    
         
             
              when '--arch'
         
     | 
| 
       74 
121 
     | 
    
         
             
                architecture = arg.to_sym
         
     | 
| 
      
 122 
     | 
    
         
            +
              when '--check'
         
     | 
| 
      
 123 
     | 
    
         
            +
                check_only = true
         
     | 
| 
       75 
124 
     | 
    
         
             
              when '--features'
         
     | 
| 
       76 
125 
     | 
    
         
             
                show_features = true
         
     | 
| 
      
 126 
     | 
    
         
            +
              when '--help'
         
     | 
| 
      
 127 
     | 
    
         
            +
                puts USAGE
         
     | 
| 
      
 128 
     | 
    
         
            +
                puts HELP
         
     | 
| 
      
 129 
     | 
    
         
            +
                exit
         
     | 
| 
       77 
130 
     | 
    
         
             
              when '--output-file'
         
     | 
| 
       78 
131 
     | 
    
         
             
                output_file = arg
         
     | 
| 
       79 
132 
     | 
    
         
             
              when '--output-format'
         
     | 
| 
         @@ -99,6 +152,24 @@ if output_format == :help 
     | 
|
| 
       99 
152 
     | 
    
         
             
              exit
         
     | 
| 
       100 
153 
     | 
    
         
             
            end
         
     | 
| 
       101 
154 
     | 
    
         | 
| 
      
 155 
     | 
    
         
            +
            if check_only
         
     | 
| 
      
 156 
     | 
    
         
            +
              input_file = get_input_file_name
         
     | 
| 
      
 157 
     | 
    
         
            +
              infile = input_file == '-' ? $stdin : open(input_file)
         
     | 
| 
      
 158 
     | 
    
         
            +
              begin
         
     | 
| 
      
 159 
     | 
    
         
            +
                parser = Voodoo::Parser.new infile
         
     | 
| 
      
 160 
     | 
    
         
            +
                generator = Voodoo::DummyGenerator.new
         
     | 
| 
      
 161 
     | 
    
         
            +
                compiler = Voodoo::Compiler.new parser, generator, nil
         
     | 
| 
      
 162 
     | 
    
         
            +
                compiler.compile
         
     | 
| 
      
 163 
     | 
    
         
            +
              rescue => error
         
     | 
| 
      
 164 
     | 
    
         
            +
                handle_error error
         
     | 
| 
      
 165 
     | 
    
         
            +
                exit 1
         
     | 
| 
      
 166 
     | 
    
         
            +
              ensure
         
     | 
| 
      
 167 
     | 
    
         
            +
                infile.close
         
     | 
| 
      
 168 
     | 
    
         
            +
              end
         
     | 
| 
      
 169 
     | 
    
         
            +
              puts 'OK'
         
     | 
| 
      
 170 
     | 
    
         
            +
              exit 0
         
     | 
| 
      
 171 
     | 
    
         
            +
            end
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
       102 
173 
     | 
    
         
             
            # Select code generator based on output format
         
     | 
| 
       103 
174 
     | 
    
         
             
            begin
         
     | 
| 
       104 
175 
     | 
    
         
             
              generator = Voodoo::CodeGenerator.get_generator :architecture => architecture,
         
     | 
| 
         @@ -124,20 +195,7 @@ if show_features 
     | 
|
| 
       124 
195 
     | 
    
         
             
              exit
         
     | 
| 
       125 
196 
     | 
    
         
             
            end
         
     | 
| 
       126 
197 
     | 
    
         | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
       128 
     | 
    
         
            -
            if ARGV.length == 1
         
     | 
| 
       129 
     | 
    
         
            -
              input_file = ARGV[0]
         
     | 
| 
       130 
     | 
    
         
            -
            else
         
     | 
| 
       131 
     | 
    
         
            -
              if ARGV.length < 1
         
     | 
| 
       132 
     | 
    
         
            -
                $stderr.puts "no input files"
         
     | 
| 
       133 
     | 
    
         
            -
              else
         
     | 
| 
       134 
     | 
    
         
            -
                $stderr.puts "Too many arguments"
         
     | 
| 
       135 
     | 
    
         
            -
              end
         
     | 
| 
       136 
     | 
    
         
            -
              $stderr.puts usage
         
     | 
| 
       137 
     | 
    
         
            -
              exit 0x80
         
     | 
| 
       138 
     | 
    
         
            -
            end
         
     | 
| 
       139 
     | 
    
         
            -
             
     | 
| 
       140 
     | 
    
         
            -
             
     | 
| 
      
 198 
     | 
    
         
            +
            input_file = get_input_file_name
         
     | 
| 
       141 
199 
     | 
    
         | 
| 
       142 
200 
     | 
    
         
             
            #
         
     | 
| 
       143 
201 
     | 
    
         
             
            # Compile
         
     | 
| 
         @@ -171,30 +229,8 @@ rescue => e 
     | 
|
| 
       171 
229 
     | 
    
         
             
                File::unlink(output_file) if File::exists?(output_file)
         
     | 
| 
       172 
230 
     | 
    
         
             
              end
         
     | 
| 
       173 
231 
     | 
    
         | 
| 
       174 
     | 
    
         
            -
               
     | 
| 
       175 
     | 
    
         
            -
               
     | 
| 
       176 
     | 
    
         
            -
              # handling is performed.
         
     | 
| 
       177 
     | 
    
         
            -
              if e.kind_of? Voodoo::Compiler::Error
         
     | 
| 
       178 
     | 
    
         
            -
                e.errors.each do |error|
         
     | 
| 
       179 
     | 
    
         
            -
                  message = ''
         
     | 
| 
       180 
     | 
    
         
            -
                  if error.start_line != nil
         
     | 
| 
       181 
     | 
    
         
            -
                    message << "#{error.start_line}: "
         
     | 
| 
       182 
     | 
    
         
            -
                    if error.input_name != nil
         
     | 
| 
       183 
     | 
    
         
            -
                      message = "#{error.input_name}:#{message}"
         
     | 
| 
       184 
     | 
    
         
            -
                    else
         
     | 
| 
       185 
     | 
    
         
            -
                      message = "line #{message}"
         
     | 
| 
       186 
     | 
    
         
            -
                    end
         
     | 
| 
       187 
     | 
    
         
            -
                  end
         
     | 
| 
       188 
     | 
    
         
            -
                  message << error.message
         
     | 
| 
       189 
     | 
    
         
            -
                  $stderr.puts message
         
     | 
| 
       190 
     | 
    
         
            -
                  if error.text != nil
         
     | 
| 
       191 
     | 
    
         
            -
                    $stderr.print "\n  #{error.text.gsub("\n", "\n  ")}\n"
         
     | 
| 
       192 
     | 
    
         
            -
                  end
         
     | 
| 
       193 
     | 
    
         
            -
                end
         
     | 
| 
       194 
     | 
    
         
            -
                exit 1
         
     | 
| 
       195 
     | 
    
         
            -
              else
         
     | 
| 
       196 
     | 
    
         
            -
                raise
         
     | 
| 
       197 
     | 
    
         
            -
              end
         
     | 
| 
      
 232 
     | 
    
         
            +
              handle_error e
         
     | 
| 
      
 233 
     | 
    
         
            +
              exit 1
         
     | 
| 
       198 
234 
     | 
    
         
             
            ensure
         
     | 
| 
       199 
235 
     | 
    
         
             
              outfile.close
         
     | 
| 
       200 
236 
     | 
    
         
             
              infile.close
         
     | 
    
        data/lib/voodoo.rb
    CHANGED
    
    | 
         @@ -10,22 +10,27 @@ require 'voodoo/parser' 
     | 
|
| 
       10 
10 
     | 
    
         
             
            # programming language designed to be a thin abstraction of the CPU's
         
     | 
| 
       11 
11 
     | 
    
         
             
            # native instruction set.
         
     | 
| 
       12 
12 
     | 
    
         
             
            #
         
     | 
| 
       13 
     | 
    
         
            -
            # The compiler consists of  
     | 
| 
      
 13 
     | 
    
         
            +
            # The compiler consists of four parts:
         
     | 
| 
       14 
14 
     | 
    
         
             
            #
         
     | 
| 
       15 
15 
     | 
    
         
             
            # 1. The parser (Voodoo::Parser), which reads 
         
     | 
| 
       16 
16 
     | 
    
         
             
            #    Voodoo[http://inglorion.net/documents/designs/voodoo/] source code and
         
     | 
| 
       17 
17 
     | 
    
         
             
            #    turns it into Ruby[http://www.ruby-lang.org/] objects.
         
     | 
| 
       18 
18 
     | 
    
         
             
            #
         
     | 
| 
       19 
     | 
    
         
            -
            # 2. The  
     | 
| 
      
 19 
     | 
    
         
            +
            # 2. The validator (Voodoo::Validator), which takes Voodoo code in Ruby
         
     | 
| 
      
 20 
     | 
    
         
            +
            #    object form and checks that it is valid. The parser calls the validator,
         
     | 
| 
      
 21 
     | 
    
         
            +
            #    so if you are using the parser to get Voodoo code, it will already have
         
     | 
| 
      
 22 
     | 
    
         
            +
            #    been validated.
         
     | 
| 
      
 23 
     | 
    
         
            +
            #
         
     | 
| 
      
 24 
     | 
    
         
            +
            # 3. The code generator (a class that implements the methods of
         
     | 
| 
       20 
25 
     | 
    
         
             
            #    Voodoo::CommonCodeGenerator), which provides methods that generate
         
     | 
| 
       21 
26 
     | 
    
         
             
            #    code for the target platform.
         
     | 
| 
       22 
27 
     | 
    
         
             
            #
         
     | 
| 
       23 
     | 
    
         
            -
            #  
     | 
| 
      
 28 
     | 
    
         
            +
            # 4. The compiler driver (Voodoo::Compiler), which reads from the parser
         
     | 
| 
       24 
29 
     | 
    
         
             
            #    and calls the appropriate methods of the code generator.
         
     | 
| 
       25 
30 
     | 
    
         
             
            #
         
     | 
| 
       26 
     | 
    
         
            -
            #  
     | 
| 
       27 
     | 
    
         
            -
            # example, you could use the code generator to generate native 
     | 
| 
       28 
     | 
    
         
            -
            # your own programming language without first creating a
         
     | 
| 
      
 31 
     | 
    
         
            +
            # The parser, validator, and code generators can be used on their own.
         
     | 
| 
      
 32 
     | 
    
         
            +
            # For example, you could use the code generator to generate native
         
     | 
| 
      
 33 
     | 
    
         
            +
            # code for your own programming language without first creating a
         
     | 
| 
       29 
34 
     | 
    
         
             
            # Voodoo[http://inglorion.net/documents/designs/voodoo/] program.
         
     | 
| 
       30 
35 
     | 
    
         
             
            #
         
     | 
| 
       31 
36 
     | 
    
         
             
            # Instead of instantiating a code generator directly, it is recommended
         
     | 
| 
         @@ -11,7 +11,7 @@ module Voodoo 
     | 
|
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                module_function
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
                #  
     | 
| 
      
 14 
     | 
    
         
            +
                # Registers a code generator.
         
     | 
| 
       15 
15 
     | 
    
         
             
                # Example:
         
     | 
| 
       16 
16 
     | 
    
         
             
                #   Voodoo::CodeGenerator.register_generator I386NasmGenerator,
         
     | 
| 
       17 
17 
     | 
    
         
             
                #                                            :architecture => :i386,
         
     | 
| 
         @@ -28,7 +28,7 @@ module Voodoo 
     | 
|
| 
       28 
28 
     | 
    
         
             
                  end
         
     | 
| 
       29 
29 
     | 
    
         
             
                end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
                #  
     | 
| 
      
 31 
     | 
    
         
            +
                # Gets a code generator for the specified parameters.
         
     | 
| 
       32 
32 
     | 
    
         
             
                def get_generator params = {}
         
     | 
| 
       33 
33 
     | 
    
         
             
                  params[:architecture] = Config.default_architecture \
         
     | 
| 
       34 
34 
     | 
    
         
             
                    unless params[:architecture]
         
     | 
| 
         @@ -44,23 +44,23 @@ module Voodoo 
     | 
|
| 
       44 
44 
     | 
    
         
             
                  end
         
     | 
| 
       45 
45 
     | 
    
         
             
                end
         
     | 
| 
       46 
46 
     | 
    
         | 
| 
       47 
     | 
    
         
            -
                # Tests if a given architecture is supported
         
     | 
| 
      
 47 
     | 
    
         
            +
                # Tests if a given architecture is supported.
         
     | 
| 
       48 
48 
     | 
    
         
             
                def architecture_supported? arch
         
     | 
| 
       49 
49 
     | 
    
         
             
                  @@generators.has_key? arch.to_sym
         
     | 
| 
       50 
50 
     | 
    
         
             
                end
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
       52 
     | 
    
         
            -
                #  
     | 
| 
      
 52 
     | 
    
         
            +
                # Gets an array of supported architectures.
         
     | 
| 
       53 
53 
     | 
    
         
             
                def architectures
         
     | 
| 
       54 
54 
     | 
    
         
             
                  @@generators.keys
         
     | 
| 
       55 
55 
     | 
    
         
             
                end
         
     | 
| 
       56 
56 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
                # Tests if a given format is supported for a given architecture
         
     | 
| 
      
 57 
     | 
    
         
            +
                # Tests if a given format is supported for a given architecture.
         
     | 
| 
       58 
58 
     | 
    
         
             
                def format_supported? arch, format
         
     | 
| 
       59 
59 
     | 
    
         
             
                  architecture_supported?(arch.to_sym) &&
         
     | 
| 
       60 
60 
     | 
    
         
             
                    @@generators[arch.to_sym].has_key?(format.to_sym)
         
     | 
| 
       61 
61 
     | 
    
         
             
                end
         
     | 
| 
       62 
62 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
                #  
     | 
| 
      
 63 
     | 
    
         
            +
                # Gets an array of supported formats for a given architecture.
         
     | 
| 
       64 
64 
     | 
    
         
             
                def formats architecture
         
     | 
| 
       65 
65 
     | 
    
         
             
                  @@generators[architecture.to_sym].keys
         
     | 
| 
       66 
66 
     | 
    
         
             
                end
         
     | 
    
        data/lib/voodoo/compiler.rb
    CHANGED
    
    | 
         @@ -23,7 +23,7 @@ module Voodoo 
     | 
|
| 
       23 
23 
     | 
    
         
             
                  end
         
     | 
| 
       24 
24 
     | 
    
         
             
                end
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
                #  
     | 
| 
      
 26 
     | 
    
         
            +
                # Initializes a compiler.
         
     | 
| 
       27 
27 
     | 
    
         
             
                #
         
     | 
| 
       28 
28 
     | 
    
         
             
                # Parameters:
         
     | 
| 
       29 
29 
     | 
    
         
             
                # [parser] the parser to be used (see Voodoo::Parser)
         
     | 
| 
         @@ -36,7 +36,7 @@ module Voodoo 
     | 
|
| 
       36 
36 
     | 
    
         
             
                  @output = output
         
     | 
| 
       37 
37 
     | 
    
         
             
                end
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
                #  
     | 
| 
      
 39 
     | 
    
         
            +
                # Performs the compilation.
         
     | 
| 
       40 
40 
     | 
    
         
             
                def compile
         
     | 
| 
       41 
41 
     | 
    
         
             
                  section = :code
         
     | 
| 
       42 
42 
     | 
    
         
             
                  errors = []
         
     | 
    
        data/lib/voodoo/config.rb
    CHANGED
    
    | 
         @@ -2,15 +2,15 @@ module Voodoo 
     | 
|
| 
       2 
2 
     | 
    
         
             
              # Methods to get and set configuration parameters
         
     | 
| 
       3 
3 
     | 
    
         
             
              module Config
         
     | 
| 
       4 
4 
     | 
    
         
             
                IMPLEMENTATION_NAME = 'Voodoo Compiler'
         
     | 
| 
       5 
     | 
    
         
            -
                IMPLEMENTATION_VERSION = '1. 
     | 
| 
      
 5 
     | 
    
         
            +
                IMPLEMENTATION_VERSION = '1.1.1'
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
                # Class that holds configuration parameters
         
     | 
| 
       8 
8 
     | 
    
         
             
                class Configuration
         
     | 
| 
       9 
9 
     | 
    
         
             
                  def initialize
         
     | 
| 
       10 
10 
     | 
    
         
             
                    @default_architecture = :auto
         
     | 
| 
       11 
11 
     | 
    
         
             
                    @default_format = :elf
         
     | 
| 
       12 
     | 
    
         
            -
                    @gas_command = "as"
         
     | 
| 
       13 
     | 
    
         
            -
                    @nasm_command = " 
     | 
| 
      
 12 
     | 
    
         
            +
                    @gas_command = "/usr/bin/as"
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @nasm_command = ""
         
     | 
| 
       14 
14 
     | 
    
         
             
                  end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
                  attr_accessor :default_format,
         
     | 
| 
         @@ -1,4 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'voodoo/generators/nasm_generator'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'set'
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            module Voodoo
         
     | 
| 
       4 
5 
     | 
    
         
             
              # = AMD64 NASM Code Generator
         
     | 
| 
         @@ -45,15 +46,25 @@ module Voodoo 
     | 
|
| 
       45 
46 
     | 
    
         
             
              #   arg_1
         
     | 
| 
       46 
47 
     | 
    
         
             
              #   :
         
     | 
| 
       47 
48 
     | 
    
         
             
              #   arg_5
         
     | 
| 
       48 
     | 
    
         
            -
              #    
     | 
| 
       49 
     | 
    
         
            -
              #    
     | 
| 
      
 49 
     | 
    
         
            +
              #   saved_r12
         
     | 
| 
      
 50 
     | 
    
         
            +
              #   :
         
     | 
| 
      
 51 
     | 
    
         
            +
              #   saved_r15
         
     | 
| 
      
 52 
     | 
    
         
            +
              #   local_4
         
     | 
| 
       50 
53 
     | 
    
         
             
              #   :
         
     | 
| 
       51 
54 
     | 
    
         
             
              #   local_n   <-- rsp
         
     | 
| 
       52 
55 
     | 
    
         
             
              #
         
     | 
| 
      
 56 
     | 
    
         
            +
              #
         
     | 
| 
      
 57 
     | 
    
         
            +
              # == Callee-Save Registers
         
     | 
| 
      
 58 
     | 
    
         
            +
              #
         
     | 
| 
      
 59 
     | 
    
         
            +
              # +rbp+, +rbx+, and +r12+ through +r15+ are callee-save registers.
         
     | 
| 
      
 60 
     | 
    
         
            +
              #
         
     | 
| 
      
 61 
     | 
    
         
            +
              # All other registers are caller-save.
         
     | 
| 
      
 62 
     | 
    
         
            +
              #
         
     | 
| 
       53 
63 
     | 
    
         
             
              class AMD64NasmGenerator < NasmGenerator
         
     | 
| 
       54 
64 
     | 
    
         
             
                def initialize params = {}
         
     | 
| 
       55 
65 
     | 
    
         
             
                  # Number of bytes in a word
         
     | 
| 
       56 
     | 
    
         
            -
                  @ 
     | 
| 
      
 66 
     | 
    
         
            +
                  @WORDSIZE_BITS = 3
         
     | 
| 
      
 67 
     | 
    
         
            +
                  @WORDSIZE = 1 << @WORDSIZE_BITS
         
     | 
| 
       57 
68 
     | 
    
         
             
                  # Word name in NASM lingo
         
     | 
| 
       58 
69 
     | 
    
         
             
                  @WORD_NAME = 'qword'
         
     | 
| 
       59 
70 
     | 
    
         
             
                  # Default alignment for code
         
     | 
| 
         @@ -63,28 +74,40 @@ module Voodoo 
     | 
|
| 
       63 
74 
     | 
    
         
             
                  # Default alignment for functions
         
     | 
| 
       64 
75 
     | 
    
         
             
                  @FUNCTION_ALIGNMENT = 16
         
     | 
| 
       65 
76 
     | 
    
         
             
                  # Register used for return values
         
     | 
| 
       66 
     | 
    
         
            -
                  @RETURN_REG =  
     | 
| 
       67 
     | 
    
         
            -
                  #  
     | 
| 
       68 
     | 
    
         
            -
                  @ 
     | 
| 
      
 77 
     | 
    
         
            +
                  @RETURN_REG = :rax
         
     | 
| 
      
 78 
     | 
    
         
            +
                  # Stack alignment restrictions
         
     | 
| 
      
 79 
     | 
    
         
            +
                  @STACK_ALIGNMENT_BITS = @WORDSIZE_BITS
         
     | 
| 
      
 80 
     | 
    
         
            +
                  @STACK_ALIGNMENT = 1 << @STACK_ALIGNMENT_BITS
         
     | 
| 
      
 81 
     | 
    
         
            +
                  @TEMPORARIES = [:r11]
         
     | 
| 
       69 
82 
     | 
    
         
             
                  # Registers used for argument passing
         
     | 
| 
       70 
     | 
    
         
            -
                  @ARG_REGS = [ 
     | 
| 
      
 83 
     | 
    
         
            +
                  @ARG_REGS = [:rdi, :rsi, :rdx, :rcx, :r8, :r9]
         
     | 
| 
      
 84 
     | 
    
         
            +
                  @NREG_ARGS = @ARG_REGS.length
         
     | 
| 
      
 85 
     | 
    
         
            +
                  # Registers used to store locals
         
     | 
| 
      
 86 
     | 
    
         
            +
                  @LOCAL_REGISTERS = [:r12, :r13, :r14, :r15]
         
     | 
| 
      
 87 
     | 
    
         
            +
                  @NLOCAL_REGISTERS = @LOCAL_REGISTERS.length
         
     | 
| 
      
 88 
     | 
    
         
            +
                  @LOCAL_REGISTERS_SET = Set.new @LOCAL_REGISTERS
         
     | 
| 
       71 
89 
     | 
    
         
             
                  # Accumulator index
         
     | 
| 
       72 
     | 
    
         
            -
                  @AX =  
     | 
| 
      
 90 
     | 
    
         
            +
                  @AX = :rax
         
     | 
| 
       73 
91 
     | 
    
         
             
                  # Base index
         
     | 
| 
       74 
     | 
    
         
            -
                  @BX =  
     | 
| 
      
 92 
     | 
    
         
            +
                  @BX = :rbx
         
     | 
| 
       75 
93 
     | 
    
         
             
                  # Count index
         
     | 
| 
       76 
     | 
    
         
            -
                  @CX =  
     | 
| 
      
 94 
     | 
    
         
            +
                  @CX = :rcx
         
     | 
| 
       77 
95 
     | 
    
         
             
                  # Data index
         
     | 
| 
       78 
     | 
    
         
            -
                  @DX =  
     | 
| 
      
 96 
     | 
    
         
            +
                  @DX = :rdx
         
     | 
| 
       79 
97 
     | 
    
         
             
                  # Base pointer
         
     | 
| 
       80 
     | 
    
         
            -
                  @BP =  
     | 
| 
      
 98 
     | 
    
         
            +
                  @BP = :rbp
         
     | 
| 
       81 
99 
     | 
    
         
             
                  # Stack pointer
         
     | 
| 
       82 
     | 
    
         
            -
                  @SP =  
     | 
| 
      
 100 
     | 
    
         
            +
                  @SP = :rsp
         
     | 
| 
      
 101 
     | 
    
         
            +
                  @SAVE_FRAME_REGISTERS = [:rbx, :r12, :r13, :r14, :r15, :rsp, :rbp]
         
     | 
| 
      
 102 
     | 
    
         
            +
                  @SAVED_FRAME_LAYOUT = {}
         
     | 
| 
      
 103 
     | 
    
         
            +
                  @SAVE_FRAME_REGISTERS.each_with_index { |r,i| @SAVED_FRAME_LAYOUT[r] = i }
         
     | 
| 
       83 
104 
     | 
    
         
             
                  super params
         
     | 
| 
       84 
105 
     | 
    
         
             
                  @features.merge! \
         
     | 
| 
       85 
106 
     | 
    
         
             
                    :'bits-per-word' => '64',
         
     | 
| 
       86 
107 
     | 
    
         
             
                    :'byte-order' => 'little-endian',
         
     | 
| 
       87 
108 
     | 
    
         
             
                    :'bytes-per-word' => '8'
         
     | 
| 
      
 109 
     | 
    
         
            +
                  @saved_registers = []
         
     | 
| 
      
 110 
     | 
    
         
            +
                  @function_end_label = nil
         
     | 
| 
       88 
111 
     | 
    
         
             
                end
         
     | 
| 
       89 
112 
     | 
    
         | 
| 
       90 
113 
     | 
    
         
             
                #
         
     | 
| 
         @@ -100,15 +123,33 @@ module Voodoo 
     | 
|
| 
       100 
123 
     | 
    
         
             
                # == Functions
         
     | 
| 
       101 
124 
     | 
    
         
             
                #
         
     | 
| 
       102 
125 
     | 
    
         | 
| 
       103 
     | 
    
         
            -
                #  
     | 
| 
      
 126 
     | 
    
         
            +
                # Emits function preamble and declare +formals+ as function arguments.
         
     | 
| 
      
 127 
     | 
    
         
            +
                def begin_function formals, nlocals
         
     | 
| 
      
 128 
     | 
    
         
            +
                  environment = Environment.new @environment
         
     | 
| 
      
 129 
     | 
    
         
            +
                  @saved_registers = []
         
     | 
| 
      
 130 
     | 
    
         
            +
                  @environment = environment
         
     | 
| 
      
 131 
     | 
    
         
            +
                  emit "push #{@BP}\nmov #{@BP}, #{@SP}\n"
         
     | 
| 
      
 132 
     | 
    
         
            +
                  formals.each_with_index do |arg,i|
         
     | 
| 
      
 133 
     | 
    
         
            +
                    @environment.add_arg arg, arg_offset(i)
         
     | 
| 
      
 134 
     | 
    
         
            +
                    comment "# #{arg} is at #{offset_reference(@environment[arg])}"
         
     | 
| 
      
 135 
     | 
    
         
            +
                    emit "push #{@ARG_REGS[i]}\n" if i < @NREG_ARGS
         
     | 
| 
      
 136 
     | 
    
         
            +
                  end
         
     | 
| 
      
 137 
     | 
    
         
            +
                  emit "sub #{@SP}, #{nlocals * @WORDSIZE}\n"
         
     | 
| 
      
 138 
     | 
    
         
            +
                  number_of_register_locals(nlocals).times do |i|
         
     | 
| 
      
 139 
     | 
    
         
            +
                    register = @LOCAL_REGISTERS[i]
         
     | 
| 
      
 140 
     | 
    
         
            +
                    ref = offset_reference saved_local_offset(i)
         
     | 
| 
      
 141 
     | 
    
         
            +
                    emit "mov #{ref}, #{register}\n"
         
     | 
| 
      
 142 
     | 
    
         
            +
                    @saved_registers << register
         
     | 
| 
      
 143 
     | 
    
         
            +
                  end
         
     | 
| 
      
 144 
     | 
    
         
            +
                  @function_end_label = gensym
         
     | 
| 
      
 145 
     | 
    
         
            +
                end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                # Calls a function.
         
     | 
| 
       104 
148 
     | 
    
         
             
                def call func, *args
         
     | 
| 
       105 
     | 
    
         
            -
                  emit "; call #{func} #{args.join ' '}\n"
         
     | 
| 
       106 
149 
     | 
    
         
             
                  # First couple of arguments go in registers
         
     | 
| 
       107 
     | 
    
         
            -
                  register_args = args[0..( 
     | 
| 
      
 150 
     | 
    
         
            +
                  register_args = args[0..(@NREG_ARGS - 1)] || []
         
     | 
| 
       108 
151 
     | 
    
         
             
                  # Rest of arguments go on the stack
         
     | 
| 
       109 
     | 
    
         
            -
                  stack_args = args[ 
     | 
| 
       110 
     | 
    
         
            -
                  emit "; register_args: #{register_args.inspect}\n"
         
     | 
| 
       111 
     | 
    
         
            -
                  emit "; stack_args: #{stack_args.inspect}\n"
         
     | 
| 
      
 152 
     | 
    
         
            +
                  stack_args = args[@NREG_ARGS..-1] || []
         
     | 
| 
       112 
153 
     | 
    
         
             
                  # Push stack arguments
         
     | 
| 
       113 
154 
     | 
    
         
             
                  stack_args.reverse.each { |arg| push_qword arg }
         
     | 
| 
       114 
155 
     | 
    
         
             
                  # Load register arguments
         
     | 
| 
         @@ -120,13 +161,15 @@ module Voodoo 
     | 
|
| 
       120 
161 
     | 
    
         
             
                    end
         
     | 
| 
       121 
162 
     | 
    
         
             
                  end
         
     | 
| 
       122 
163 
     | 
    
         
             
                  # Call function
         
     | 
| 
       123 
     | 
    
         
            -
                   
     | 
| 
       124 
     | 
    
         
            -
             
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
                     
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
                     
     | 
| 
      
 164 
     | 
    
         
            +
                  with_temporary do |temporary|
         
     | 
| 
      
 165 
     | 
    
         
            +
                    value_ref = load_value func, temporary
         
     | 
| 
      
 166 
     | 
    
         
            +
                    emit "xor rax, rax\n"
         
     | 
| 
      
 167 
     | 
    
         
            +
                    # If value_ref is a symbol, use PLT-relative addressing
         
     | 
| 
      
 168 
     | 
    
         
            +
                    if global?(func)
         
     | 
| 
      
 169 
     | 
    
         
            +
                      emit "call #{value_ref} wrt ..plt\n"
         
     | 
| 
      
 170 
     | 
    
         
            +
                    else
         
     | 
| 
      
 171 
     | 
    
         
            +
                      emit "call #{value_ref}\n"
         
     | 
| 
      
 172 
     | 
    
         
            +
                    end
         
     | 
| 
       130 
173 
     | 
    
         
             
                  end
         
     | 
| 
       131 
174 
     | 
    
         
             
                  # Clean up stack
         
     | 
| 
       132 
175 
     | 
    
         
             
                  unless stack_args.empty?
         
     | 
| 
         @@ -134,20 +177,33 @@ module Voodoo 
     | 
|
| 
       134 
177 
     | 
    
         
             
                  end
         
     | 
| 
       135 
178 
     | 
    
         
             
                end
         
     | 
| 
       136 
179 
     | 
    
         | 
| 
       137 
     | 
    
         
            -
                #  
     | 
| 
       138 
     | 
    
         
            -
                def  
     | 
| 
       139 
     | 
    
         
            -
                   
     | 
| 
       140 
     | 
    
         
            -
                   
     | 
| 
       141 
     | 
    
         
            -
             
     | 
| 
       142 
     | 
    
         
            -
                     
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
             
     | 
| 
      
 180 
     | 
    
         
            +
                # Ends a function body.
         
     | 
| 
      
 181 
     | 
    
         
            +
                def end_function
         
     | 
| 
      
 182 
     | 
    
         
            +
                  label @function_end_label
         
     | 
| 
      
 183 
     | 
    
         
            +
                  # Restore saved registers
         
     | 
| 
      
 184 
     | 
    
         
            +
                  @saved_registers.each_with_index do |register,i|
         
     | 
| 
      
 185 
     | 
    
         
            +
                    ref = offset_reference saved_local_offset(i)
         
     | 
| 
      
 186 
     | 
    
         
            +
                    emit "mov #{register}, #{ref}\n"
         
     | 
| 
      
 187 
     | 
    
         
            +
                  end
         
     | 
| 
      
 188 
     | 
    
         
            +
                  # Destroy frame.
         
     | 
| 
      
 189 
     | 
    
         
            +
                  emit "leave\n"
         
     | 
| 
      
 190 
     | 
    
         
            +
                  # Return.
         
     | 
| 
      
 191 
     | 
    
         
            +
                  emit "ret\n"
         
     | 
| 
      
 192 
     | 
    
         
            +
                  if @environment == @top_level
         
     | 
| 
      
 193 
     | 
    
         
            +
                    raise "Cannot end function when not in a function"
         
     | 
| 
      
 194 
     | 
    
         
            +
                  else
         
     | 
| 
      
 195 
     | 
    
         
            +
                    @environment = @top_level
         
     | 
| 
       145 
196 
     | 
    
         
             
                  end
         
     | 
| 
       146 
197 
     | 
    
         
             
                end
         
     | 
| 
       147 
198 
     | 
    
         | 
| 
       148 
     | 
    
         
            -
                #  
     | 
| 
      
 199 
     | 
    
         
            +
                # Returns from a function.
         
     | 
| 
      
 200 
     | 
    
         
            +
                def ret *words
         
     | 
| 
      
 201 
     | 
    
         
            +
                  eval_expr words, @AX unless words.empty?
         
     | 
| 
      
 202 
     | 
    
         
            +
                  goto @function_end_label
         
     | 
| 
      
 203 
     | 
    
         
            +
                end
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
                # Calls a function, re-using the current call frame if possible.
         
     | 
| 
       149 
206 
     | 
    
         
             
                def tail_call func, *args
         
     | 
| 
       150 
     | 
    
         
            -
                  emit "; tail-call #{func} #{args.join ' '}\n"
         
     | 
| 
       151 
207 
     | 
    
         
             
                  # Compute required number of stack words
         
     | 
| 
       152 
208 
     | 
    
         
             
                  nstackargs = number_of_stack_arguments args.length
         
     | 
| 
       153 
209 
     | 
    
         
             
                  # If we need more stack arguments than we have now,
         
     | 
| 
         @@ -155,62 +211,69 @@ module Voodoo 
     | 
|
| 
       155 
211 
     | 
    
         
             
                  if nstackargs > number_of_stack_arguments(@environment.args)
         
     | 
| 
       156 
212 
     | 
    
         
             
                    emit "; Not enough space for proper tail call; using regular call\n"
         
     | 
| 
       157 
213 
     | 
    
         
             
                    ret :call, func, *args
         
     | 
| 
       158 
     | 
    
         
            -
                   
     | 
| 
      
 214 
     | 
    
         
            +
                  else
         
     | 
| 
       159 
215 
     | 
    
         | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
       161 
     | 
    
         
            -
             
     | 
| 
       162 
     | 
    
         
            -
             
     | 
| 
       163 
     | 
    
         
            -
             
     | 
| 
       164 
     | 
    
         
            -
             
     | 
| 
      
 216 
     | 
    
         
            +
                    # If any arguments are going to be overwritten before they are
         
     | 
| 
      
 217 
     | 
    
         
            +
                    # used, save them to new local variables and use those instead.
         
     | 
| 
      
 218 
     | 
    
         
            +
                    (args.length - 1).downto(@NREG_ARGS) do |i|
         
     | 
| 
      
 219 
     | 
    
         
            +
                      arg = args[i]
         
     | 
| 
      
 220 
     | 
    
         
            +
                      next unless symbol?(arg)
         
     | 
| 
      
 221 
     | 
    
         
            +
                      old_arg_offset = @environment[arg]
         
     | 
| 
      
 222 
     | 
    
         
            +
                      next if old_arg_offset == nil || old_arg_offset < 0
         
     | 
| 
      
 223 
     | 
    
         
            +
                      # arg is an argument that was passed on the stack.
         
     | 
| 
      
 224 
     | 
    
         
            +
                      new_arg_offset = arg_offset i
         
     | 
| 
      
 225 
     | 
    
         
            +
                      next unless old_arg_offset > new_arg_offset
         
     | 
| 
      
 226 
     | 
    
         
            +
                      # arg will be overwritten before it is used.
         
     | 
| 
      
 227 
     | 
    
         
            +
                      # Save it in a newly created temporary variable,
         
     | 
| 
      
 228 
     | 
    
         
            +
                      # then use that instead.
         
     | 
| 
      
 229 
     | 
    
         
            +
                      newsym = @environment.gensym
         
     | 
| 
      
 230 
     | 
    
         
            +
                      let newsym, arg
         
     | 
| 
      
 231 
     | 
    
         
            +
                      args[i] = newsym
         
     | 
| 
      
 232 
     | 
    
         
            +
                    end
         
     | 
| 
       165 
233 
     | 
    
         | 
| 
       166 
     | 
    
         
            -
                     
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
       168 
     | 
    
         
            -
                       
     | 
| 
       169 
     | 
    
         
            -
             
     | 
| 
       170 
     | 
    
         
            -
                        # Save value
         
     | 
| 
      
 234 
     | 
    
         
            +
                    # Same for the function we will be calling.
         
     | 
| 
      
 235 
     | 
    
         
            +
                    if symbol?(func)
         
     | 
| 
      
 236 
     | 
    
         
            +
                      offset = @environment[func]
         
     | 
| 
      
 237 
     | 
    
         
            +
                      if offset != nil && offset > 0
         
     | 
| 
       171 
238 
     | 
    
         
             
                        newsym = @environment.gensym
         
     | 
| 
       172 
     | 
    
         
            -
                        let newsym,  
     | 
| 
       173 
     | 
    
         
            -
                         
     | 
| 
       174 
     | 
    
         
            -
                        if i >= 0
         
     | 
| 
       175 
     | 
    
         
            -
                          args[i] = newsym
         
     | 
| 
       176 
     | 
    
         
            -
                        else
         
     | 
| 
       177 
     | 
    
         
            -
                          func = newsym
         
     | 
| 
       178 
     | 
    
         
            -
                        end
         
     | 
| 
      
 239 
     | 
    
         
            +
                        let newsym, func
         
     | 
| 
      
 240 
     | 
    
         
            +
                        func = newsym
         
     | 
| 
       179 
241 
     | 
    
         
             
                      end
         
     | 
| 
       180 
242 
     | 
    
         
             
                    end
         
     | 
| 
       181 
     | 
    
         
            -
                    i = i - 1
         
     | 
| 
       182 
     | 
    
         
            -
                  end
         
     | 
| 
       183 
243 
     | 
    
         | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       185 
     | 
    
         
            -
             
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
             
     | 
| 
       188 
     | 
    
         
            -
             
     | 
| 
       189 
     | 
    
         
            -
             
     | 
| 
       190 
     | 
    
         
            -
             
     | 
| 
       191 
     | 
    
         
            -
             
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
     | 
    
         
            -
             
     | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
      
 244 
     | 
    
         
            +
                    # Set stack arguments
         
     | 
| 
      
 245 
     | 
    
         
            +
                    if args.length > @NREG_ARGS
         
     | 
| 
      
 246 
     | 
    
         
            +
                      (args.length - 1).downto(@NREG_ARGS).each do |i|
         
     | 
| 
      
 247 
     | 
    
         
            +
                        arg = args[i]
         
     | 
| 
      
 248 
     | 
    
         
            +
             
     | 
| 
      
 249 
     | 
    
         
            +
                        with_temporary do |temporary|
         
     | 
| 
      
 250 
     | 
    
         
            +
                          value_ref = load_value arg, temporary
         
     | 
| 
      
 251 
     | 
    
         
            +
                          newarg_ref = load_arg i
         
     | 
| 
      
 252 
     | 
    
         
            +
                          # Elide code if source is same as destination
         
     | 
| 
      
 253 
     | 
    
         
            +
                          unless value_ref == newarg_ref
         
     | 
| 
      
 254 
     | 
    
         
            +
                            emit "mov #{temporary}, #{value_ref}\n"
         
     | 
| 
      
 255 
     | 
    
         
            +
                            emit "mov #{newarg_ref}, #{temporary}\n"
         
     | 
| 
      
 256 
     | 
    
         
            +
                          end
         
     | 
| 
      
 257 
     | 
    
         
            +
                        end
         
     | 
| 
       195 
258 
     | 
    
         
             
                      end
         
     | 
| 
       196 
259 
     | 
    
         
             
                    end
         
     | 
| 
       197 
     | 
    
         
            -
                  end
         
     | 
| 
       198 
260 
     | 
    
         | 
| 
       199 
     | 
    
         
            -
             
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
       201 
     | 
    
         
            -
             
     | 
| 
       202 
     | 
    
         
            -
             
     | 
| 
       203 
     | 
    
         
            -
             
     | 
| 
      
 261 
     | 
    
         
            +
                    # Set register arguments
         
     | 
| 
      
 262 
     | 
    
         
            +
                    number_of_register_arguments(args.length).times do |i|
         
     | 
| 
      
 263 
     | 
    
         
            +
                      register = @ARG_REGS[i]
         
     | 
| 
      
 264 
     | 
    
         
            +
                      load_value_into_register args[i], register
         
     | 
| 
      
 265 
     | 
    
         
            +
                    end
         
     | 
| 
       204 
266 
     | 
    
         | 
| 
       205 
     | 
    
         
            -
             
     | 
| 
       206 
     | 
    
         
            -
             
     | 
| 
       207 
     | 
    
         
            -
             
     | 
| 
       208 
     | 
    
         
            -
             
     | 
| 
       209 
     | 
    
         
            -
             
     | 
| 
       210 
     | 
    
         
            -
             
     | 
| 
       211 
     | 
    
         
            -
             
     | 
| 
       212 
     | 
    
         
            -
             
     | 
| 
       213 
     | 
    
         
            -
             
     | 
| 
      
 267 
     | 
    
         
            +
                    # Tail call
         
     | 
| 
      
 268 
     | 
    
         
            +
                    func_ref = load_value func, @BX
         
     | 
| 
      
 269 
     | 
    
         
            +
                    emit "leave\n"
         
     | 
| 
      
 270 
     | 
    
         
            +
                    set_register @AX, 0
         
     | 
| 
      
 271 
     | 
    
         
            +
                    # If func_ref is a symbol, use PLT-relative addressing
         
     | 
| 
      
 272 
     | 
    
         
            +
                    if global?(func)
         
     | 
| 
      
 273 
     | 
    
         
            +
                      emit "jmp #{func_ref} wrt ..plt\n"
         
     | 
| 
      
 274 
     | 
    
         
            +
                    else
         
     | 
| 
      
 275 
     | 
    
         
            +
                      emit "jmp #{func_ref}\n"
         
     | 
| 
      
 276 
     | 
    
         
            +
                    end
         
     | 
| 
       214 
277 
     | 
    
         
             
                  end
         
     | 
| 
       215 
278 
     | 
    
         
             
                end
         
     | 
| 
       216 
279 
     | 
    
         | 
| 
         @@ -218,8 +281,8 @@ module Voodoo 
     | 
|
| 
       218 
281 
     | 
    
         
             
                # == Loading Values
         
     | 
| 
       219 
282 
     | 
    
         
             
                #
         
     | 
| 
       220 
283 
     | 
    
         | 
| 
       221 
     | 
    
         
            -
                #  
     | 
| 
       222 
     | 
    
         
            -
                def load_arg n 
     | 
| 
      
 284 
     | 
    
         
            +
                # Loads the value of the nth argument.
         
     | 
| 
      
 285 
     | 
    
         
            +
                def load_arg n
         
     | 
| 
       223 
286 
     | 
    
         
             
                  if register_argument?(n)
         
     | 
| 
       224 
287 
     | 
    
         
             
                    # Arguments that were originally passed in a register
         
     | 
| 
       225 
288 
     | 
    
         
             
                    # are now below rbp
         
     | 
| 
         @@ -227,58 +290,68 @@ module Voodoo 
     | 
|
| 
       227 
290 
     | 
    
         
             
                  else
         
     | 
| 
       228 
291 
     | 
    
         
             
                    # Arguments that were originally passed on the stack
         
     | 
| 
       229 
292 
     | 
    
         
             
                    # are now above rbp, starting 2 words above it
         
     | 
| 
       230 
     | 
    
         
            -
                    "[rbp + #{(n + 2 -  
     | 
| 
      
 293 
     | 
    
         
            +
                    "[rbp + #{(n + 2 - @NREG_ARGS) * @WORDSIZE}]"
         
     | 
| 
       231 
294 
     | 
    
         
             
                  end
         
     | 
| 
       232 
295 
     | 
    
         
             
                end
         
     | 
| 
       233 
296 
     | 
    
         | 
| 
       234 
     | 
    
         
            -
                #  
     | 
| 
       235 
     | 
    
         
            -
                def  
     | 
| 
       236 
     | 
    
         
            -
                  #  
     | 
| 
       237 
     | 
    
         
            -
                  # local variables are offset by
         
     | 
| 
       238 
     | 
    
         
            -
                  # number_of_register_arguments(number_of_arguments)
         
     | 
| 
       239 
     | 
    
         
            -
                  # words.
         
     | 
| 
       240 
     | 
    
         
            -
                  offset = number_of_register_arguments(@environment.args) * @WORDSIZE
         
     | 
| 
       241 
     | 
    
         
            -
                  "[rbp - #{offset + (n + 1) * @WORDSIZE}]"
         
     | 
| 
      
 297 
     | 
    
         
            +
                # Loads a symbol from the global offset table.
         
     | 
| 
      
 298 
     | 
    
         
            +
                def load_symbol_from_got symbol, reg
         
     | 
| 
      
 299 
     | 
    
         
            +
                  "[rel #{symbol} wrt ..gotpc]"
         
     | 
| 
       242 
300 
     | 
    
         
             
                end
         
     | 
| 
       243 
301 
     | 
    
         | 
| 
       244 
302 
     | 
    
         
             
                #
         
     | 
| 
       245 
     | 
    
         
            -
                # ==  
     | 
| 
      
 303 
     | 
    
         
            +
                # == Miscellaneous
         
     | 
| 
       246 
304 
     | 
    
         
             
                #
         
     | 
| 
       247 
305 
     | 
    
         | 
| 
       248 
     | 
    
         
            -
                #  
     | 
| 
       249 
     | 
    
         
            -
                def  
     | 
| 
       250 
     | 
    
         
            -
                   
     | 
| 
       251 
     | 
    
         
            -
             
     | 
| 
       252 
     | 
    
         
            -
                   
     | 
| 
       253 
     | 
    
         
            -
             
     | 
| 
      
 306 
     | 
    
         
            +
                # Returns the offset from rbp at which the nth argument is stored.
         
     | 
| 
      
 307 
     | 
    
         
            +
                def arg_offset n
         
     | 
| 
      
 308 
     | 
    
         
            +
                  if n < @NREG_ARGS
         
     | 
| 
      
 309 
     | 
    
         
            +
                    (n + 1) * -@WORDSIZE
         
     | 
| 
      
 310 
     | 
    
         
            +
                  else
         
     | 
| 
      
 311 
     | 
    
         
            +
                    (n - @NREG_ARGS) * @WORDSIZE + 2 * @WORDSIZE
         
     | 
| 
      
 312 
     | 
    
         
            +
                  end
         
     | 
| 
       254 
313 
     | 
    
         
             
                end
         
     | 
| 
       255 
314 
     | 
    
         | 
| 
       256 
     | 
    
         
            -
                #
         
     | 
| 
       257 
     | 
    
         
            -
                #  
     | 
| 
       258 
     | 
    
         
            -
                 
     | 
| 
      
 315 
     | 
    
         
            +
                # If the nth local is stored in a register, returns that register.
         
     | 
| 
      
 316 
     | 
    
         
            +
                # Otherwise, returns the offset from the frame pointer.
         
     | 
| 
      
 317 
     | 
    
         
            +
                def local_offset_or_register n
         
     | 
| 
      
 318 
     | 
    
         
            +
                  if n < @NLOCAL_REGISTERS
         
     | 
| 
      
 319 
     | 
    
         
            +
                    @LOCAL_REGISTERS[n]
         
     | 
| 
      
 320 
     | 
    
         
            +
                  else
         
     | 
| 
      
 321 
     | 
    
         
            +
                    (n + number_of_register_arguments + 1) * -@WORDSIZE
         
     | 
| 
      
 322 
     | 
    
         
            +
                  end
         
     | 
| 
      
 323 
     | 
    
         
            +
                end
         
     | 
| 
       259 
324 
     | 
    
         | 
| 
       260 
     | 
    
         
            -
                #  
     | 
| 
      
 325 
     | 
    
         
            +
                # Loads a value and push it on the stack.
         
     | 
| 
       261 
326 
     | 
    
         
             
                def push_qword value
         
     | 
| 
       262 
     | 
    
         
            -
                   
     | 
| 
       263 
     | 
    
         
            -
             
     | 
| 
      
 327 
     | 
    
         
            +
                  with_temporary do |temporary|
         
     | 
| 
      
 328 
     | 
    
         
            +
                    value_ref = load_value value, temporary
         
     | 
| 
      
 329 
     | 
    
         
            +
                    emit "push qword #{value_ref}\n"
         
     | 
| 
      
 330 
     | 
    
         
            +
                  end
         
     | 
| 
       264 
331 
     | 
    
         
             
                end
         
     | 
| 
       265 
332 
     | 
    
         | 
| 
       266 
     | 
    
         
            -
                #  
     | 
| 
      
 333 
     | 
    
         
            +
                # Calculates the number of register arguments,
         
     | 
| 
       267 
334 
     | 
    
         
             
                # given the total number of arguments.
         
     | 
| 
       268 
     | 
    
         
            -
                 
     | 
| 
       269 
     | 
    
         
            -
             
     | 
| 
       270 
     | 
    
         
            -
                def number_of_register_arguments n = nil
         
     | 
| 
       271 
     | 
    
         
            -
                  if n.nil?
         
     | 
| 
       272 
     | 
    
         
            -
                    @ARG_REGS.length
         
     | 
| 
       273 
     | 
    
         
            -
                  else
         
     | 
| 
       274 
     | 
    
         
            -
                    [@ARG_REGS.length, n].min
         
     | 
| 
       275 
     | 
    
         
            -
                  end
         
     | 
| 
      
 335 
     | 
    
         
            +
                def number_of_register_arguments n = @environment.args
         
     | 
| 
      
 336 
     | 
    
         
            +
                  n < @NREG_ARGS ? n : @NREG_ARGS
         
     | 
| 
       276 
337 
     | 
    
         
             
                end
         
     | 
| 
       277 
338 
     | 
    
         | 
| 
       278 
     | 
    
         
            -
                #  
     | 
| 
      
 339 
     | 
    
         
            +
                # Calculates the number of locals that are stored in registers.
         
     | 
| 
      
 340 
     | 
    
         
            +
                def number_of_register_locals n = @environment.locals
         
     | 
| 
      
 341 
     | 
    
         
            +
                  n < @NLOCAL_REGISTERS ? n : @NLOCAL_REGISTERS
         
     | 
| 
      
 342 
     | 
    
         
            +
                end
         
     | 
| 
      
 343 
     | 
    
         
            +
             
     | 
| 
      
 344 
     | 
    
         
            +
                # Calculates the number of stack arguments,
         
     | 
| 
       279 
345 
     | 
    
         
             
                # given the total number of arguments.
         
     | 
| 
       280 
     | 
    
         
            -
                def number_of_stack_arguments n
         
     | 
| 
       281 
     | 
    
         
            -
                   
     | 
| 
      
 346 
     | 
    
         
            +
                def number_of_stack_arguments n = @environment.args
         
     | 
| 
      
 347 
     | 
    
         
            +
                  x = n - @NREG_ARGS
         
     | 
| 
      
 348 
     | 
    
         
            +
                  x < 0 ? 0 : x
         
     | 
| 
      
 349 
     | 
    
         
            +
                end
         
     | 
| 
      
 350 
     | 
    
         
            +
             
     | 
| 
      
 351 
     | 
    
         
            +
                # Calculates the number of locals that are stored on the stack.
         
     | 
| 
      
 352 
     | 
    
         
            +
                def number_of_stack_locals n = @environment.locals
         
     | 
| 
      
 353 
     | 
    
         
            +
                  x = n - @NLOCAL_REGISTERS
         
     | 
| 
      
 354 
     | 
    
         
            +
                  x < 0 ? 0 : x
         
     | 
| 
       282 
355 
     | 
    
         
             
                end
         
     | 
| 
       283 
356 
     | 
    
         | 
| 
       284 
357 
     | 
    
         
             
                # Tests if the nth argument is a register argument.
         
     | 
| 
         @@ -286,6 +359,11 @@ module Voodoo 
     | 
|
| 
       286 
359 
     | 
    
         
             
                  n < number_of_register_arguments
         
     | 
| 
       287 
360 
     | 
    
         
             
                end
         
     | 
| 
       288 
361 
     | 
    
         | 
| 
      
 362 
     | 
    
         
            +
                # Returns the offset of the nth saved local.
         
     | 
| 
      
 363 
     | 
    
         
            +
                def saved_local_offset n
         
     | 
| 
      
 364 
     | 
    
         
            +
                  (number_of_register_arguments + n + 1) * -@WORDSIZE
         
     | 
| 
      
 365 
     | 
    
         
            +
                end
         
     | 
| 
      
 366 
     | 
    
         
            +
             
     | 
| 
       289 
367 
     | 
    
         
             
              end
         
     | 
| 
       290 
368 
     | 
    
         | 
| 
       291 
369 
     | 
    
         
             
              # Register class
         
     |