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 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
- }