wilson 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +4 -2
- data/History.txt +21 -0
- data/README.txt +21 -4
- data/Rakefile +2 -2
- data/bench.rb +74 -67
- data/lib/wilson.rb +142 -110
- data/test/test_wilson.rb +37 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
@@ -1,2 +1,4 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
�@���s�C;�n(Oـ��5�|��n���SNB���NKD��"d��w�ϑ�r���9�*��a���}�+
|
2
|
+
|
3
|
+
��ܟ<�wU
|
4
|
+
KyԆ�P?oҖ�<��s-nE���j�[u��̝x�t-����QK41�-��M2O'd;�&d`�w=�z��x�,Y~��y��������>�� �}s �N!�v�ń�sy����NT$V�Q��[��Z��w��
|
data/History.txt
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
=== 1.1.0 / 2009-05-08
|
2
|
+
|
3
|
+
* 1 major enhancement:
|
4
|
+
|
5
|
+
* Added Object#asm for inline assembly. 100% ruby, no C.
|
6
|
+
|
7
|
+
* 7 minor enhancements:
|
8
|
+
|
9
|
+
* Added arg(n) for cleanly accessing ruby arguments.
|
10
|
+
* Added debugging output if $DEBUG.
|
11
|
+
* Added defasm and asm test cases.
|
12
|
+
* Added from_ruby and sped up to_ruby a teeny amount.
|
13
|
+
* Improved benchmark code
|
14
|
+
* Refactored ASM DSL to Object#assemble.
|
15
|
+
* Sped up tests a fair amount by optimizing supportsProcessor.
|
16
|
+
|
17
|
+
* 2 bug fixes:
|
18
|
+
|
19
|
+
* Found a bug in the nasm manual that wilson parses. Fixed SAR.
|
20
|
+
* Found a bug in the nasm manual that wilson parses. Fixed cmp.
|
21
|
+
|
1
22
|
=== 1.0.1 / 2009-04-22
|
2
23
|
|
3
24
|
* 3 minor enhancements:
|
data/README.txt
CHANGED
@@ -13,18 +13,35 @@ is about as metal as you can get (and it is easier to spell than
|
|
13
13
|
|
14
14
|
== FEATURES/PROBLEMS:
|
15
15
|
|
16
|
-
* Generates x86 machine code directly
|
17
|
-
*
|
16
|
+
* Generates x86 machine code directly. No dependencies. No system calls.
|
17
|
+
* Registers ruby methods with #defasm, or run inline assembly with #asm.
|
18
|
+
* Terrible, yet, awesome.
|
18
19
|
|
19
20
|
== SYNOPSIS:
|
20
21
|
|
21
22
|
class X
|
22
23
|
defasm :superfast_meaning_of_life do
|
23
|
-
eax.mov 42
|
24
|
+
eax.mov 42
|
25
|
+
to_ruby eax # ruby fixnums = (n << 1) + 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def inline_asm_example
|
29
|
+
n = 1000
|
30
|
+
|
31
|
+
asm :count_to_n do
|
32
|
+
eax.xor eax
|
33
|
+
count = self.label
|
34
|
+
eax.inc
|
35
|
+
eax.cmp n
|
36
|
+
jne count
|
37
|
+
|
38
|
+
to_ruby eax
|
39
|
+
end
|
24
40
|
end
|
25
41
|
end
|
26
42
|
|
27
43
|
p X.new.superfast_meaning_of_life # => 42
|
44
|
+
p X.new.inline_asm_example # => 1000
|
28
45
|
|
29
46
|
== REQUIREMENTS:
|
30
47
|
|
@@ -38,7 +55,7 @@ is about as metal as you can get (and it is easier to spell than
|
|
38
55
|
|
39
56
|
(The MIT License)
|
40
57
|
|
41
|
-
Copyright (c) 2008 Ryan Davis, Seattle.rb
|
58
|
+
Copyright (c) 2008-2009 Ryan Davis, Seattle.rb
|
42
59
|
|
43
60
|
Permission is hereby granted, free of charge, to any person obtaining
|
44
61
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
@@ -4,7 +4,7 @@ require 'rubygems'
|
|
4
4
|
require 'hoe'
|
5
5
|
require './lib/wilson.rb'
|
6
6
|
|
7
|
-
Hoe.new('wilson', Wilson::VERSION) do |p|
|
7
|
+
h = Hoe.new('wilson', Wilson::VERSION) do |p|
|
8
8
|
p.rubyforge_name = 'seattlerb'
|
9
9
|
p.developer('Ryan Davis', 'ryand-ruby@zenspider.com')
|
10
10
|
end
|
@@ -12,7 +12,7 @@ end
|
|
12
12
|
namespace :test do
|
13
13
|
desc "profiles your tests"
|
14
14
|
task :prof do
|
15
|
-
|
15
|
+
ruby "-S zenprofile #{h.make_test_cmd}"
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
data/bench.rb
CHANGED
@@ -2,14 +2,31 @@
|
|
2
2
|
|
3
3
|
# % rm -r ~/.ruby_inline; ./bench.rb 1_000_000 1_000
|
4
4
|
# # of iterations = 1000000
|
5
|
+
# $n = 1000
|
6
|
+
#
|
5
7
|
# user system total real
|
6
|
-
# null_time 0.
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
8
|
+
# null_time 0.120000 0.000000 0.120000 ( 0.122507)
|
9
|
+
# cee_nil 0.280000 0.000000 0.280000 ( 0.279552)
|
10
|
+
# asm_nil 0.280000 0.000000 0.280000 ( 0.275498)
|
11
|
+
# ruby_nil 0.370000 0.000000 0.370000 ( 0.372142)
|
12
|
+
# cee 0.830000 0.010000 0.840000 ( 0.837607)
|
13
|
+
# asm2 0.830000 0.000000 0.830000 ( 0.839430)
|
14
|
+
# asm 3.520000 0.000000 3.520000 ( 3.542521)
|
15
|
+
# ruby 98.970000 0.430000 99.400000 (101.903256)
|
16
|
+
#
|
17
|
+
# % rm -r ~/.ruby_inline; ./bench.rb 10_000_000 100
|
18
|
+
# # of iterations = 10000000
|
19
|
+
# $n = 100
|
20
|
+
#
|
21
|
+
# user system total real
|
22
|
+
# null_time 1.220000 0.000000 1.220000 ( 1.243087)
|
23
|
+
# cee_nil 2.780000 0.010000 2.790000 ( 2.825447)
|
24
|
+
# asm_nil 2.760000 0.010000 2.770000 ( 2.770936)
|
25
|
+
# ruby_nil 3.710000 0.000000 3.710000 ( 3.735188)
|
26
|
+
# cee 3.560000 0.010000 3.570000 ( 3.581262)
|
27
|
+
# asm2 3.450000 0.010000 3.460000 ( 3.481769)
|
28
|
+
# asm 5.990000 0.010000 6.000000 ( 6.042270)
|
29
|
+
# ruby 95.460000 0.300000 95.760000 ( 96.578792)
|
13
30
|
|
14
31
|
$: << 'lib'
|
15
32
|
require 'wilson'
|
@@ -18,96 +35,74 @@ require 'inline'
|
|
18
35
|
require 'benchmark'
|
19
36
|
|
20
37
|
max = (ARGV.shift || 10_000_000).to_i
|
21
|
-
|
38
|
+
n = (ARGV.shift || 100).to_i
|
22
39
|
|
23
40
|
class Counter
|
24
41
|
inline do |builder|
|
25
42
|
builder.c "VALUE cee_nil() { return Qnil;}"
|
26
|
-
builder.c "long cee() { long i; for (i = 0;i
|
43
|
+
builder.c "long cee(int n) { long i; for (i = 0;i<n+1;i++) {}; return i;}"
|
27
44
|
end
|
28
45
|
|
29
|
-
# 00000f7a pushl %ebp
|
30
|
-
# 00000f7b xorl %eax,%eax
|
31
|
-
# 00000f7d movl %esp,%ebp
|
32
|
-
# 00000f7f incl %eax
|
33
|
-
# 00000f80 cmpl $0x000003e8,%eax
|
34
|
-
# 00000f85 jne 0x00000f7f
|
35
|
-
# 00000f87 leave
|
36
|
-
# 00000f88 movw $0x07d1,%ax
|
37
|
-
# 00000f8c ret
|
38
|
-
|
39
46
|
defasm :asm_nil do
|
40
47
|
eax.mov 4
|
41
48
|
end
|
42
49
|
|
43
|
-
defasm :asm do
|
44
|
-
eax.
|
45
|
-
|
50
|
+
defasm :asm, :n do # naive version
|
51
|
+
eax.xor eax
|
52
|
+
|
53
|
+
ecx.mov arg(0)
|
54
|
+
from_ruby ecx
|
55
|
+
ecx.inc
|
56
|
+
|
46
57
|
count = self.label
|
47
|
-
eax.
|
58
|
+
eax.inc
|
48
59
|
count.loop
|
49
60
|
|
50
|
-
|
51
|
-
eax.inc
|
61
|
+
to_ruby eax
|
52
62
|
end
|
53
63
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
# 00000012 E2FB loop 0xf
|
62
|
-
# 00000014 01C0 add eax,eax
|
63
|
-
# 00000016 40 inc eax
|
64
|
-
# 00000017 5F pop edi
|
65
|
-
# 00000018 5E pop esi
|
66
|
-
# 00000019 C9 leave
|
67
|
-
# 0000001A C3 ret
|
68
|
-
|
69
|
-
defasm :asm2 do
|
70
|
-
eax.mov 0
|
64
|
+
defasm :asm2, :n do
|
65
|
+
eax.xor eax
|
66
|
+
|
67
|
+
edx.mov arg(0)
|
68
|
+
from_ruby edx
|
69
|
+
edx.inc
|
70
|
+
|
71
71
|
count = self.label
|
72
72
|
eax.inc
|
73
|
-
eax.cmp
|
74
|
-
|
73
|
+
eax.cmp edx
|
74
|
+
jnz count
|
75
75
|
|
76
|
-
|
77
|
-
eax.inc
|
76
|
+
to_ruby eax
|
78
77
|
end
|
79
78
|
|
80
|
-
# 00000000 55 push ebp
|
81
|
-
# 00000001 89E5 mov ebp,esp
|
82
|
-
# 00000003 B800000000 mov eax,0x0
|
83
|
-
# 00000008 40 inc eax
|
84
|
-
# 00000009 3DE8030000 cmp eax,0x3e8
|
85
|
-
# 0000000E 75F8 jnz 0x8
|
86
|
-
# 00000010 01C0 add eax,eax
|
87
|
-
# 00000012 40 inc eax
|
88
|
-
# 00000013 C9 leave
|
89
|
-
# 00000014 C3 ret
|
90
|
-
|
91
79
|
def ruby_nil
|
92
80
|
nil
|
93
81
|
end
|
94
82
|
|
95
|
-
def ruby
|
96
|
-
|
83
|
+
def ruby n
|
84
|
+
(n+1).times do; end
|
97
85
|
end
|
98
86
|
end
|
99
87
|
|
100
88
|
counter = Counter.new
|
101
89
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
90
|
+
%w(cee_nil asm_nil ruby_nil).each do |name|
|
91
|
+
eval "abort 'bad #{name}' unless counter.#{name}.nil? "
|
92
|
+
end
|
93
|
+
|
94
|
+
%w(cee asm2 asm ruby).each do |name|
|
95
|
+
eval "
|
96
|
+
x = counter.#{name}(n)
|
97
|
+
warn \"%5s = %4d\" % [name, x] if $DEBUG
|
98
|
+
abort 'bad #{name}' unless x == n + 1
|
99
|
+
"
|
100
|
+
end
|
101
|
+
|
102
|
+
exit 0 if $DEBUG
|
108
103
|
|
109
104
|
puts "# of iterations = #{max}"
|
110
|
-
puts "
|
105
|
+
puts "n = #{n}"
|
111
106
|
puts
|
112
107
|
Benchmark::bm(20) do |x|
|
113
108
|
x.report("null_time") do
|
@@ -116,7 +111,7 @@ Benchmark::bm(20) do |x|
|
|
116
111
|
end
|
117
112
|
end
|
118
113
|
|
119
|
-
%w(cee_nil asm_nil ruby_nil
|
114
|
+
%w(cee_nil asm_nil ruby_nil).each do |name|
|
120
115
|
eval "
|
121
116
|
x.report(#{name.inspect}) do
|
122
117
|
for i in 0..max do
|
@@ -125,4 +120,16 @@ Benchmark::bm(20) do |x|
|
|
125
120
|
end
|
126
121
|
"
|
127
122
|
end
|
123
|
+
|
124
|
+
funcs = %w(cee asm2 asm)
|
125
|
+
funcs << 'ruby' if ENV['PAIN']
|
126
|
+
funcs.each do |name|
|
127
|
+
eval "
|
128
|
+
x.report(#{name.inspect}) do
|
129
|
+
for i in 0..max do
|
130
|
+
counter.#{name}(n)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
"
|
134
|
+
end
|
128
135
|
end
|
data/lib/wilson.rb
CHANGED
@@ -3,80 +3,6 @@
|
|
3
3
|
require 'dl'
|
4
4
|
require 'dl/import'
|
5
5
|
|
6
|
-
module Ruby
|
7
|
-
extend DL::Importable
|
8
|
-
|
9
|
-
typealias "VALUE", "unsigned long", proc { |v| v.object_id << 1 }
|
10
|
-
|
11
|
-
dlload "libruby.dylib"
|
12
|
-
|
13
|
-
extern "void rb_define_method(VALUE, char*, void*, int)"
|
14
|
-
end
|
15
|
-
|
16
|
-
class Object
|
17
|
-
def r
|
18
|
-
self.object_id
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class Integer
|
23
|
-
def r
|
24
|
-
(self.object_id << 1) + 1
|
25
|
-
end
|
26
|
-
|
27
|
-
def inspect
|
28
|
-
"0x#{to_s 16}"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
ASM = []
|
33
|
-
|
34
|
-
class Module
|
35
|
-
def defasm name, *args, &block
|
36
|
-
asm = Wilson::MachineCodeX86.new
|
37
|
-
|
38
|
-
asm.ebp.push
|
39
|
-
asm.ebp.mov asm.esp
|
40
|
-
|
41
|
-
asm.esi.push
|
42
|
-
asm.edi.push
|
43
|
-
|
44
|
-
size = asm.stream.size
|
45
|
-
|
46
|
-
asm.instance_eval(&block)
|
47
|
-
|
48
|
-
if asm.stream.size == size # return nil
|
49
|
-
warn "returning nil for #{self}##{name}"
|
50
|
-
asm.eax.mov 4
|
51
|
-
end
|
52
|
-
|
53
|
-
asm.edi.pop
|
54
|
-
asm.esi.pop
|
55
|
-
|
56
|
-
asm.leave
|
57
|
-
asm.ret
|
58
|
-
|
59
|
-
code = asm.stream.pack("C*")
|
60
|
-
|
61
|
-
if $DEBUG then
|
62
|
-
path = "#{name}.obj"
|
63
|
-
File.open path, "wb" do |f|
|
64
|
-
f.write code
|
65
|
-
end
|
66
|
-
|
67
|
-
p name
|
68
|
-
puts code.unpack("C*").map { |n| "%02X" % n }.join(' ')
|
69
|
-
system "ndisasm -u #{path}"
|
70
|
-
|
71
|
-
File.unlink path
|
72
|
-
end
|
73
|
-
|
74
|
-
ptr = code.to_ptr
|
75
|
-
ASM << ptr
|
76
|
-
Ruby.rb_define_method self, name.to_s, ptr, 0
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
6
|
class Object
|
81
7
|
def subclass_responsibility; raise "subclass responsibility" end
|
82
8
|
def no!; false end
|
@@ -92,38 +18,20 @@ class Object
|
|
92
18
|
alias :special_register? :no!
|
93
19
|
end
|
94
20
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
class Array
|
108
|
-
def second
|
109
|
-
self[1]
|
110
|
-
end
|
111
|
-
|
112
|
-
def push_D integer
|
113
|
-
self.push(*[integer].pack("V").unpack("C4"))
|
114
|
-
end
|
115
|
-
|
116
|
-
def push_B integer
|
117
|
-
self << (integer & 255)
|
118
|
-
end
|
119
|
-
|
120
|
-
def push_W integer
|
121
|
-
self.push((integer & 255), (integer >> 8 & 255))
|
122
|
-
end
|
123
|
-
end
|
21
|
+
##
|
22
|
+
# Wilson is a pure ruby x86 assembler. No, really. Worst Idea Evar.
|
23
|
+
#
|
24
|
+
# Why "wilson"? I wanted to name it "metal", but there is an existing
|
25
|
+
# project with that name... So I'm naming it after Wilson Bilkovich, who
|
26
|
+
# is about as metal as you can get (and it is easier to spell than
|
27
|
+
# "bilkovich", even tho that sounds more metal).
|
28
|
+
#
|
29
|
+
# Wilson is a port (and extension) of the smalltalk x86 assembler by
|
30
|
+
# Michael Lucas-Smith. I came across it when he presented it at
|
31
|
+
# Smalltalk SuperPowers at OOPSLA 2008.
|
124
32
|
|
125
33
|
module Wilson
|
126
|
-
VERSION = '1.0
|
34
|
+
VERSION = '1.1.0'
|
127
35
|
|
128
36
|
##
|
129
37
|
# Assembler parses the NASM documentation and creates Command
|
@@ -156,6 +64,11 @@ module Wilson
|
|
156
64
|
FMULTO fpureg ; DC C8+r [8086,FPU]
|
157
65
|
FSUBTO fpureg ; DC E8+r [8086,FPU]
|
158
66
|
FSUBRTO fpureg ; DC E0+r [8086,FPU]
|
67
|
+
|
68
|
+
CMP r/m16,imm8 ; o16 83 /7 ib [8086]
|
69
|
+
CMP r/m32,imm8 ; o32 83 /7 ib [386]
|
70
|
+
SAR r/m16,1 ; o16 D1 /7 [8086]
|
71
|
+
SAR r/m32,1 ; o32 D1 /7 [386]
|
159
72
|
'
|
160
73
|
end
|
161
74
|
|
@@ -263,6 +176,7 @@ module Wilson
|
|
263
176
|
(self.class.nasm + self.class.nasm_fixes).each_line do |line|
|
264
177
|
self.process_line line.strip.sub(/^# /, '')
|
265
178
|
end
|
179
|
+
|
266
180
|
self
|
267
181
|
end
|
268
182
|
end
|
@@ -622,13 +536,15 @@ module Wilson
|
|
622
536
|
end
|
623
537
|
|
624
538
|
def supportsProcessor instructionProcessors
|
625
|
-
|
539
|
+
# TODO: can still be improved. hashes, caching... something
|
540
|
+
! (processors & instructionProcessors).empty?
|
626
541
|
end
|
627
542
|
|
628
543
|
def instructions
|
629
544
|
self.cachedInstructions ||= @instructions.select { |e|
|
630
545
|
self.supportsProcessor e.processors
|
631
546
|
}
|
547
|
+
self.cachedInstructions
|
632
548
|
end
|
633
549
|
|
634
550
|
def method_missing msg, *args
|
@@ -863,10 +779,18 @@ module Wilson
|
|
863
779
|
self.edi = Register.on_id_bits self, 7, 32
|
864
780
|
end
|
865
781
|
|
782
|
+
def arg n
|
783
|
+
ebp + (n+3) * 4
|
784
|
+
end
|
785
|
+
|
866
786
|
def to_ruby reg
|
867
|
-
reg.
|
787
|
+
reg.shl 1
|
868
788
|
reg.inc
|
869
789
|
end
|
790
|
+
|
791
|
+
def from_ruby reg
|
792
|
+
reg.shr 1
|
793
|
+
end
|
870
794
|
end
|
871
795
|
|
872
796
|
##
|
@@ -1201,6 +1125,114 @@ module Wilson
|
|
1201
1125
|
end
|
1202
1126
|
end # module Wilson
|
1203
1127
|
|
1128
|
+
module Ruby
|
1129
|
+
extend DL::Importable
|
1130
|
+
|
1131
|
+
typealias "VALUE", "unsigned long", proc { |v| v.object_id << 1 }
|
1132
|
+
|
1133
|
+
dlload "libruby.dylib"
|
1134
|
+
|
1135
|
+
extern "void rb_define_method(VALUE, char*, void*, int)"
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
class Integer
|
1139
|
+
def m
|
1140
|
+
address = Wilson::Address.new
|
1141
|
+
address.offset = self
|
1142
|
+
address
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
def immediate_value?
|
1146
|
+
true
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
def inspect
|
1150
|
+
"0x#{to_s 16}"
|
1151
|
+
end if $DEBUG
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
class Array
|
1155
|
+
def second
|
1156
|
+
self[1]
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
def push_D integer
|
1160
|
+
self.push(*[integer].pack("V").unpack("C4"))
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
def push_B integer
|
1164
|
+
self << (integer & 255)
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
def push_W integer
|
1168
|
+
self.push((integer & 255), (integer >> 8 & 255))
|
1169
|
+
end
|
1170
|
+
end
|
1171
|
+
|
1172
|
+
ASM = []
|
1173
|
+
|
1174
|
+
class Module
|
1175
|
+
def defasm name, *args, &block
|
1176
|
+
code = assemble(args.size, &block)
|
1177
|
+
ptr = code.to_ptr
|
1178
|
+
|
1179
|
+
ASM << ptr
|
1180
|
+
Ruby.rb_define_method self, name.to_s, ptr, args.size
|
1181
|
+
end
|
1182
|
+
end
|
1183
|
+
|
1184
|
+
class Object
|
1185
|
+
def assemble arg_count = 0, &block
|
1186
|
+
asm = Wilson::MachineCodeX86.new
|
1187
|
+
|
1188
|
+
# TODO: enter?
|
1189
|
+
asm.ebp.push
|
1190
|
+
asm.ebp.mov asm.esp
|
1191
|
+
|
1192
|
+
size = asm.stream.size
|
1193
|
+
|
1194
|
+
asm.instance_eval(&block)
|
1195
|
+
|
1196
|
+
if asm.stream.size == size # return nil
|
1197
|
+
warn "returning nil for #{self}##{name}"
|
1198
|
+
asm.eax.mov 4
|
1199
|
+
end
|
1200
|
+
|
1201
|
+
asm.leave
|
1202
|
+
asm.ret
|
1203
|
+
|
1204
|
+
code = asm.stream.pack("C*")
|
1205
|
+
|
1206
|
+
if $DEBUG then
|
1207
|
+
path = "#{$$}.obj"
|
1208
|
+
File.open path, "wb" do |f|
|
1209
|
+
f.write code
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
puts code.unpack("C*").map { |n| "%02X" % n }.join(' ')
|
1213
|
+
system "ndisasm -u #{path}"
|
1214
|
+
|
1215
|
+
File.unlink path
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
code
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
@@asm = {}
|
1222
|
+
def asm(name, *args, &block)
|
1223
|
+
code = @@asm[name] ||= assemble(&block).to_ptr
|
1224
|
+
|
1225
|
+
return execute_asm(code) # code is the function pointer, wrapped
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
defasm :execute_asm, :code do
|
1229
|
+
eax.mov ebp + 0x0c # grab code
|
1230
|
+
eax.mov eax + 0x10 # unwrap function pointer field
|
1231
|
+
eax.mov eax.m # dereference the pointer
|
1232
|
+
eax.call # call the function pointer
|
1233
|
+
end
|
1234
|
+
end
|
1235
|
+
|
1204
1236
|
__END__
|
1205
1237
|
|
1206
1238
|
# The Netwide Assembler: NASM
|
@@ -1861,8 +1893,8 @@ __END__
|
|
1861
1893
|
# CMP r/m16,imm16 ; o16 81 /0 iw [8086]
|
1862
1894
|
# CMP r/m32,imm32 ; o32 81 /0 id [386]
|
1863
1895
|
|
1864
|
-
#
|
1865
|
-
#
|
1896
|
+
# DEADCMP r/m16,imm8 ; o16 83 /0 ib [8086]
|
1897
|
+
# DEADCMP r/m32,imm8 ; o32 83 /0 ib [386]
|
1866
1898
|
|
1867
1899
|
# CMP AL,imm8 ; 3C ib [8086]
|
1868
1900
|
# CMP AX,imm16 ; o16 3D iw [8086]
|
@@ -4222,10 +4254,10 @@ __END__
|
|
4222
4254
|
# SAR r/m8,1 ; D0 /0 [8086]
|
4223
4255
|
# SAR r/m8,CL ; D2 /0 [8086]
|
4224
4256
|
# SAR r/m8,imm8 ; C0 /0 ib [286]
|
4225
|
-
#
|
4257
|
+
# xxSAR r/m16,1 ; o16 D1 /0 [8086]
|
4226
4258
|
# SAR r/m16,CL ; o16 D3 /0 [8086]
|
4227
4259
|
# SAR r/m16,imm8 ; o16 C1 /0 ib [286]
|
4228
|
-
#
|
4260
|
+
# xxSAR r/m32,1 ; o32 D1 /0 [386]
|
4229
4261
|
# SAR r/m32,CL ; o32 D3 /0 [386]
|
4230
4262
|
# SAR r/m32,imm8 ; o32 C1 /0 ib [386]
|
4231
4263
|
|
data/test/test_wilson.rb
CHANGED
@@ -2,6 +2,22 @@
|
|
2
2
|
require 'test/unit'
|
3
3
|
require 'wilson'
|
4
4
|
|
5
|
+
class X
|
6
|
+
def counter
|
7
|
+
n = 1000
|
8
|
+
|
9
|
+
asm :count_to_n do
|
10
|
+
eax.mov 0
|
11
|
+
count = self.label
|
12
|
+
eax.inc
|
13
|
+
eax.cmp n
|
14
|
+
jne count
|
15
|
+
|
16
|
+
to_ruby eax
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
5
21
|
class TestWilson < Test::Unit::TestCase
|
6
22
|
# MachineCodeX86Test initialize-release
|
7
23
|
|
@@ -12,6 +28,27 @@ class TestWilson < Test::Unit::TestCase
|
|
12
28
|
|
13
29
|
attr_reader :asm, :stream
|
14
30
|
|
31
|
+
defasm :passthrough, :n do
|
32
|
+
eax.mov arg(0) # add n as-is
|
33
|
+
end
|
34
|
+
|
35
|
+
defasm :add_to_n, :n do
|
36
|
+
eax.mov arg(0) # set eax to n
|
37
|
+
eax.add 2 # increment ruby fixnum directly
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_wtf_inline!
|
41
|
+
assert_equal 1000, X.new.counter
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_wtf1?
|
45
|
+
assert_equal 42, add_to_n(41)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_wtf2?
|
49
|
+
assert_equal 42, passthrough(42)
|
50
|
+
end
|
51
|
+
|
15
52
|
# MachineCodeX86Test testing ow/od
|
16
53
|
|
17
54
|
def test_mov_offset_eax
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wilson
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Davis
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
30
30
|
FBHgymkyj/AOSqKRIpXPhjC6
|
31
31
|
-----END CERTIFICATE-----
|
32
32
|
|
33
|
-
date: 2009-
|
33
|
+
date: 2009-05-08 00:00:00 -07:00
|
34
34
|
default_executable:
|
35
35
|
dependencies:
|
36
36
|
- !ruby/object:Gem::Dependency
|
metadata.gz.sig
CHANGED
Binary file
|