jit_buffer 1.0.0 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34c56015392868597d86a358c2db6427ac291e2a1824328977142f2c3badccdf
4
- data.tar.gz: 2b17329aea7966304cf009634fbd572bdc746471d6771ee741209b86a618ae5d
3
+ metadata.gz: 042d1a4c8ee681237a3829d1ae950a726558383b26262d828aab558e6bb51bfa
4
+ data.tar.gz: 7ef264b37a228f8845938c7d10162bb4b39aee153dd8f8a11b59774a1688423b
5
5
  SHA512:
6
- metadata.gz: 1ee6388bf6a313f18b3ada0039eba6b9c065966009b8f19f1c3ffe7522a0faabef7e912e189414917a8e6a0e3019142f1efb76f8ea388f14b140e2411cd55d13
7
- data.tar.gz: 5087a35a661273910c5be37dcd868113a5ef39ce6beeeb38c919b4cb2403fc589a122a8f9f60b83a970b7d0706d14b3fbfe1c90e7259ecb4a043f174b78165aa
6
+ metadata.gz: 5c3eb5c03d5c91ed27cb1dd13448e6a5ef95ade94388e9fd0f50c6bcda6d7d449432b0d1c06425ca5c795f9df74e19465ca6823f6d34a18023557437ae3e7bc3
7
+ data.tar.gz: c57d3e2fc3c0102b3de9a9f6a132b11d3b77d0d57653845ede834035b8fdff95ea2e633e140240fab56e01e50cef99d385c97eea0241d4ab2a219a737efb3d93
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Rakefile CHANGED
@@ -6,6 +6,3 @@ Rake::TestTask.new(:test) do |t|
6
6
  t.verbose = true
7
7
  t.warning = true
8
8
  end
9
-
10
- require 'rake/extensiontask'
11
- Rake::ExtensionTask.new("jit_buffer")
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.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
- x = super(MMAP.mmap_buffer(size), size)
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 >= @size
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 >= @size
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.pthread_jit_write_protect_np true
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.pthread_jit_write_protect_np false
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
@@ -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
- insns = [
50
- movz(0, 42),
51
- ret
52
- ].pack("L<L<")
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 insns
102
+ jit.write bytes.pack("C*")
57
103
 
58
104
  jit.executable!
59
- func = jit.to_function([], Fiddle::TYPE_INT)
60
- assert_equal 42, func.call
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
- # ARM instructions
116
- def movz reg, imm
117
- insn = 0b0_10_100101_00_0000000000000000_00000
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.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-03-11 00:00:00.000000000 Z
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
@@ -1,10 +0,0 @@
1
- require 'mkmf'
2
-
3
- raise unless have_header "sys/mman.h"
4
-
5
- have_const 'MAP_JIT', 'sys/mman.h'
6
-
7
- have_func 'pthread_jit_write_protect_np'
8
- have_func 'sys_icache_invalidate'
9
-
10
- create_makefile('jit_buffer')
@@ -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
- }