jit_buffer 1.0.0 → 1.0.3
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.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/Rakefile +0 -3
- data/jit_buffer.gemspec +0 -1
- data/lib/jit_buffer.rb +54 -11
- data/test/jit_buffer_test.rb +56 -19
- metadata +4 -6
- data/ext/jit_buffer/extconf.rb +0 -10
- data/ext/jit_buffer/jit_buffer.c +0 -59
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 042d1a4c8ee681237a3829d1ae950a726558383b26262d828aab558e6bb51bfa
|
|
4
|
+
data.tar.gz: 7ef264b37a228f8845938c7d10162bb4b39aee153dd8f8a11b59774a1688423b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5c3eb5c03d5c91ed27cb1dd13448e6a5ef95ade94388e9fd0f50c6bcda6d7d449432b0d1c06425ca5c795f9df74e19465ca6823f6d34a18023557437ae3e7bc3
|
|
7
|
+
data.tar.gz: c57d3e2fc3c0102b3de9a9f6a132b11d3b77d0d57653845ede834035b8fdff95ea2e633e140240fab56e01e50cef99d385c97eea0241d4ab2a219a737efb3d93
|
data/Gemfile
ADDED
data/Rakefile
CHANGED
data/jit_buffer.gemspec
CHANGED
|
@@ -18,7 +18,6 @@ Gem::Specification.new do |spec|
|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
19
|
|
|
20
20
|
spec.require_paths = ["lib"]
|
|
21
|
-
spec.extensions = ["ext/jit_buffer/extconf.rb"]
|
|
22
21
|
|
|
23
22
|
spec.add_development_dependency "rake", '~> 13.0'
|
|
24
23
|
spec.add_development_dependency "minitest", '~> 5.15'
|
data/lib/jit_buffer.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require "jit_buffer.so"
|
|
2
1
|
require "fiddle"
|
|
3
2
|
|
|
4
3
|
class Fiddle::Function
|
|
@@ -9,7 +8,7 @@ class Fiddle::Function
|
|
|
9
8
|
end unless Fiddle::Function.method_defined?(:to_proc)
|
|
10
9
|
|
|
11
10
|
class JITBuffer
|
|
12
|
-
VERSION = '1.0.
|
|
11
|
+
VERSION = '1.0.3'
|
|
13
12
|
|
|
14
13
|
class Exception < StandardError
|
|
15
14
|
end
|
|
@@ -23,6 +22,20 @@ class JITBuffer
|
|
|
23
22
|
module MMAP
|
|
24
23
|
include Fiddle
|
|
25
24
|
|
|
25
|
+
PROT_READ = 0x01
|
|
26
|
+
PROT_WRITE = 0x02
|
|
27
|
+
PROT_EXEC = 0x04
|
|
28
|
+
|
|
29
|
+
MAP_PRIVATE = 0x02
|
|
30
|
+
|
|
31
|
+
if RUBY_PLATFORM =~ /darwin/
|
|
32
|
+
MAP_ANON = 0x1000
|
|
33
|
+
MAP_JIT = 0x800
|
|
34
|
+
else
|
|
35
|
+
MAP_ANON = 0x20
|
|
36
|
+
MAP_JIT = 0x0
|
|
37
|
+
end
|
|
38
|
+
|
|
26
39
|
def self.make_function name, args, ret
|
|
27
40
|
ptr = Handle::DEFAULT[name]
|
|
28
41
|
func = Function.new ptr, args, ret, name: name
|
|
@@ -42,26 +55,52 @@ class JITBuffer
|
|
|
42
55
|
|
|
43
56
|
make_function "mprotect", [TYPE_VOIDP, TYPE_SIZE_T, TYPE_INT], TYPE_INT
|
|
44
57
|
|
|
58
|
+
begin
|
|
59
|
+
make_function "pthread_jit_write_protect_np", [TYPE_INT], TYPE_VOID
|
|
60
|
+
make_function "sys_icache_invalidate", [TYPE_VOIDP, -TYPE_INT], TYPE_VOID
|
|
61
|
+
rescue Fiddle::DLError
|
|
62
|
+
end
|
|
63
|
+
|
|
45
64
|
def self.mmap_buffer size
|
|
46
65
|
ptr = mmap 0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON | MAP_JIT, -1, 0
|
|
47
66
|
ptr.size = size
|
|
48
67
|
ptr
|
|
49
68
|
end
|
|
69
|
+
|
|
70
|
+
if respond_to?(:pthread_jit_write_protect_np)
|
|
71
|
+
# MacOS
|
|
72
|
+
def self.set_writeable ptr
|
|
73
|
+
MMAP.pthread_jit_write_protect_np 0
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.set_executable ptr
|
|
77
|
+
MMAP.pthread_jit_write_protect_np 1
|
|
78
|
+
MMAP.sys_icache_invalidate ptr, ptr.size
|
|
79
|
+
end
|
|
80
|
+
else
|
|
81
|
+
# Linux
|
|
82
|
+
def self.set_writeable ptr
|
|
83
|
+
MMAP.mprotect ptr, ptr.size, PROT_READ | PROT_WRITE
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def self.set_executable ptr
|
|
87
|
+
MMAP.mprotect ptr, ptr.size, PROT_READ | PROT_EXEC
|
|
88
|
+
end
|
|
89
|
+
end
|
|
50
90
|
end
|
|
51
91
|
|
|
52
92
|
def self.new size
|
|
53
|
-
|
|
54
|
-
MMAP.pthread_jit_write_protect_np(true)
|
|
55
|
-
x
|
|
93
|
+
super(MMAP.mmap_buffer(size), size)
|
|
56
94
|
end
|
|
57
95
|
|
|
58
|
-
attr_reader :pos
|
|
96
|
+
attr_reader :pos, :size
|
|
59
97
|
|
|
60
98
|
def initialize memory, size
|
|
61
99
|
@writeable = false
|
|
62
100
|
@memory = memory
|
|
63
101
|
@size = size
|
|
64
102
|
@pos = 0
|
|
103
|
+
executable!
|
|
65
104
|
end
|
|
66
105
|
|
|
67
106
|
def putc byte
|
|
@@ -73,7 +112,7 @@ class JITBuffer
|
|
|
73
112
|
|
|
74
113
|
def write bytes
|
|
75
114
|
raise(ReadOnlyException, "Buffer is read only!") unless @writeable
|
|
76
|
-
raise OutOfBoundsException if pos + bytes.bytesize
|
|
115
|
+
raise OutOfBoundsException if pos + bytes.bytesize > @size
|
|
77
116
|
@memory[pos, bytes.length] = bytes
|
|
78
117
|
@pos += bytes.bytesize
|
|
79
118
|
end
|
|
@@ -86,7 +125,7 @@ class JITBuffer
|
|
|
86
125
|
end
|
|
87
126
|
|
|
88
127
|
def read len
|
|
89
|
-
raise(OutOfBoundsException, "You've gone too far!") if pos + len
|
|
128
|
+
raise(OutOfBoundsException, "You've gone too far!") if pos + len > @size
|
|
90
129
|
x = @memory[pos, pos + len]
|
|
91
130
|
@pos += len
|
|
92
131
|
x
|
|
@@ -101,17 +140,21 @@ class JITBuffer
|
|
|
101
140
|
end
|
|
102
141
|
|
|
103
142
|
def executable!
|
|
104
|
-
MMAP.
|
|
105
|
-
MMAP.sys_icache_invalidate @memory.to_i, @size
|
|
143
|
+
MMAP.set_executable @memory.to_i
|
|
106
144
|
@writeable = false
|
|
107
145
|
end
|
|
108
146
|
|
|
109
147
|
def writeable!
|
|
110
|
-
MMAP.
|
|
148
|
+
MMAP.set_writeable @memory.to_i
|
|
111
149
|
@writeable = true
|
|
112
150
|
end
|
|
113
151
|
|
|
114
152
|
def to_function params, ret
|
|
115
153
|
Fiddle::Function.new @memory.to_i, params, ret
|
|
116
154
|
end
|
|
155
|
+
|
|
156
|
+
# Get the address of the executable memory
|
|
157
|
+
def to_i
|
|
158
|
+
@memory.to_i
|
|
159
|
+
end
|
|
117
160
|
end
|
data/test/jit_buffer_test.rb
CHANGED
|
@@ -2,6 +2,49 @@ require "helper"
|
|
|
2
2
|
require "jit_buffer"
|
|
3
3
|
|
|
4
4
|
class JITBufferTest < Minitest::Test
|
|
5
|
+
def test_fill_buffer_with_putc
|
|
6
|
+
jit = JITBuffer.new 4096
|
|
7
|
+
str = [0xCC] * 4096
|
|
8
|
+
jit.writeable!
|
|
9
|
+
str.each { |c| jit.putc c }
|
|
10
|
+
assert_equal 4096, jit.pos
|
|
11
|
+
jit.seek 0
|
|
12
|
+
|
|
13
|
+
bytes = []
|
|
14
|
+
4096.times { bytes << (jit.getc & 0xFF) }
|
|
15
|
+
assert_equal 4096, jit.pos
|
|
16
|
+
assert_equal str, bytes
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_fill_buffer_read_with_getc
|
|
20
|
+
jit = JITBuffer.new 4096
|
|
21
|
+
str = ([0xCC] * 4096).pack("C*")
|
|
22
|
+
jit.writeable!
|
|
23
|
+
jit.write(str)
|
|
24
|
+
assert_equal 4096, jit.pos
|
|
25
|
+
jit.seek 0
|
|
26
|
+
|
|
27
|
+
bytes = []
|
|
28
|
+
4096.times { bytes << jit.getc }
|
|
29
|
+
assert_equal 4096, jit.pos
|
|
30
|
+
assert_equal str, bytes.pack("C*")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_fill_buffer
|
|
34
|
+
jit = JITBuffer.new 4096
|
|
35
|
+
str = ([0xCC] * 4096).pack("C*")
|
|
36
|
+
jit.writeable!
|
|
37
|
+
jit.write(str)
|
|
38
|
+
assert_equal 4096, jit.pos
|
|
39
|
+
jit.seek 0
|
|
40
|
+
assert_equal str, jit.read(4096)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_size
|
|
44
|
+
jit = JITBuffer.new 4096
|
|
45
|
+
assert_equal 4096, jit.size
|
|
46
|
+
end
|
|
47
|
+
|
|
5
48
|
def test_make_writeable
|
|
6
49
|
jit = JITBuffer.new 4096
|
|
7
50
|
jit.writeable!
|
|
@@ -46,18 +89,21 @@ class JITBufferTest < Minitest::Test
|
|
|
46
89
|
|
|
47
90
|
def test_execute
|
|
48
91
|
jit = JITBuffer.new 4096
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
92
|
+
|
|
93
|
+
bytes = [0x48, 0xc7, 0xc0, 0x2b, 0x00, 0x00, 0x00, # x86_64 mov rax, 0x2b
|
|
94
|
+
0xc3, # x86_64 ret
|
|
95
|
+
0xeb, 0xf6, # x86 jmp
|
|
96
|
+
0x80, 0xd2, # ARM movz X11, 0x7b7
|
|
97
|
+
0x60, 0x05, 0x80, 0xd2, # ARM movz X0, #0x2b
|
|
98
|
+
0xc0, 0x03, 0x5f, 0xd6] # ARM ret
|
|
53
99
|
|
|
54
100
|
jit.writeable!
|
|
55
101
|
|
|
56
|
-
jit.write
|
|
102
|
+
jit.write bytes.pack("C*")
|
|
57
103
|
|
|
58
104
|
jit.executable!
|
|
59
|
-
func = jit.
|
|
60
|
-
assert_equal
|
|
105
|
+
func = Fiddle::Function.new(jit.to_i + 8, [], Fiddle::TYPE_INT)
|
|
106
|
+
assert_equal 0x2b, func.call
|
|
61
107
|
end
|
|
62
108
|
|
|
63
109
|
def test_invalid_write
|
|
@@ -112,17 +158,8 @@ class JITBufferTest < Minitest::Test
|
|
|
112
158
|
end
|
|
113
159
|
end
|
|
114
160
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
insn |= (1 << 31) # 64 bit
|
|
119
|
-
insn |= (imm << 5) # immediate
|
|
120
|
-
insn |= reg # reg
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def ret xn = 30
|
|
124
|
-
insn = 0b1101011_0_0_10_11111_0000_0_0_00000_00000
|
|
125
|
-
insn |= (xn << 5)
|
|
126
|
-
insn
|
|
161
|
+
def test_to_i
|
|
162
|
+
jit = JITBuffer.new 4096
|
|
163
|
+
assert jit.to_i
|
|
127
164
|
end
|
|
128
165
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jit_buffer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aaron Patterson
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-07-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -56,16 +56,14 @@ description: A JIT Buffer object for Ruby.
|
|
|
56
56
|
email:
|
|
57
57
|
- tenderlove@ruby-lang.org
|
|
58
58
|
executables: []
|
|
59
|
-
extensions:
|
|
60
|
-
- ext/jit_buffer/extconf.rb
|
|
59
|
+
extensions: []
|
|
61
60
|
extra_rdoc_files: []
|
|
62
61
|
files:
|
|
63
62
|
- CODE_OF_CONDUCT.md
|
|
63
|
+
- Gemfile
|
|
64
64
|
- LICENSE
|
|
65
65
|
- README.md
|
|
66
66
|
- Rakefile
|
|
67
|
-
- ext/jit_buffer/extconf.rb
|
|
68
|
-
- ext/jit_buffer/jit_buffer.c
|
|
69
67
|
- jit_buffer.gemspec
|
|
70
68
|
- lib/jit_buffer.rb
|
|
71
69
|
- test/helper.rb
|
data/ext/jit_buffer/extconf.rb
DELETED
data/ext/jit_buffer/jit_buffer.c
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
#include <ruby.h>
|
|
2
|
-
#include <sys/mman.h>
|
|
3
|
-
#include <mach/vm_prot.h>
|
|
4
|
-
#include <mach/mach_init.h>
|
|
5
|
-
#include <pthread.h>
|
|
6
|
-
|
|
7
|
-
#if HAVE_SYS_ICACHE_INVALIDATE
|
|
8
|
-
#include <libkern/OSCacheControl.h>
|
|
9
|
-
#endif
|
|
10
|
-
|
|
11
|
-
#if HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
|
|
12
|
-
static VALUE
|
|
13
|
-
rb_pthread_jit_write_protect_np(VALUE mod, VALUE v)
|
|
14
|
-
{
|
|
15
|
-
if (RTEST(v)) {
|
|
16
|
-
pthread_jit_write_protect_np(1);
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
pthread_jit_write_protect_np(0);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return Qnil;
|
|
23
|
-
}
|
|
24
|
-
#endif
|
|
25
|
-
|
|
26
|
-
#if HAVE_SYS_ICACHE_INVALIDATE
|
|
27
|
-
static VALUE
|
|
28
|
-
rb_sys_icache_invalidate(VALUE mod, VALUE addr, VALUE len)
|
|
29
|
-
{
|
|
30
|
-
sys_icache_invalidate((void *)(NUM2ULONG(addr)), NUM2INT(len));
|
|
31
|
-
|
|
32
|
-
return Qnil;
|
|
33
|
-
}
|
|
34
|
-
#endif
|
|
35
|
-
|
|
36
|
-
void Init_jit_buffer() {
|
|
37
|
-
VALUE rb_cJITBuffer = rb_define_class("JITBuffer", rb_cObject);
|
|
38
|
-
VALUE rb_mMMap = rb_define_module_under(rb_cJITBuffer, "MMAP");
|
|
39
|
-
|
|
40
|
-
rb_define_const(rb_mMMap, "PROT_READ", INT2NUM(PROT_READ));
|
|
41
|
-
rb_define_const(rb_mMMap, "PROT_WRITE", INT2NUM(PROT_WRITE));
|
|
42
|
-
rb_define_const(rb_mMMap, "PROT_EXEC", INT2NUM(PROT_EXEC));
|
|
43
|
-
rb_define_const(rb_mMMap, "VM_PROT_COPY", INT2NUM(VM_PROT_COPY));
|
|
44
|
-
rb_define_const(rb_mMMap, "VM_PROT_READ", INT2NUM(VM_PROT_READ));
|
|
45
|
-
rb_define_const(rb_mMMap, "VM_PROT_EXECUTE", INT2NUM(VM_PROT_EXECUTE));
|
|
46
|
-
rb_define_const(rb_mMMap, "MAP_PRIVATE", INT2NUM(MAP_PRIVATE));
|
|
47
|
-
rb_define_const(rb_mMMap, "MAP_ANON", INT2NUM(MAP_ANON));
|
|
48
|
-
#if HAVE_CONST_MAP_JIT
|
|
49
|
-
rb_define_const(rb_mMMap, "MAP_JIT", INT2NUM(MAP_JIT));
|
|
50
|
-
#endif
|
|
51
|
-
|
|
52
|
-
#if HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
|
|
53
|
-
rb_define_module_function(rb_mMMap, "pthread_jit_write_protect_np", rb_pthread_jit_write_protect_np, 1);
|
|
54
|
-
#endif
|
|
55
|
-
|
|
56
|
-
#if HAVE_SYS_ICACHE_INVALIDATE
|
|
57
|
-
rb_define_module_function(rb_mMMap, "sys_icache_invalidate", rb_sys_icache_invalidate, 2);
|
|
58
|
-
#endif
|
|
59
|
-
}
|