wilson 1.0.1 → 1.1.0
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.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
|