@@ -63,6 +63,118 @@ static codeblock_t *ocb = NULL;
63
63
//
64
64
// The "_yjit_" part is for trying to be informative. We might want different
65
65
// suffixes for symbols meant for Rust and symbols meant for broader CRuby.
66
+
67
+ /*
68
+ void rb_yjit_mark_all_writable(uint8_t *mem_block, uint32_t mem_size) {
69
+ if (mprotect(mem_block, mem_size, PROT_READ | PROT_WRITE)) {
70
+ fprintf(stderr, "Couldn't make JIT page (%p) writeable, errno: %s", (void *)mem_block, strerror(errno));
71
+ abort();
72
+ }
73
+ }
74
+
75
+ void rb_yjit_mark_all_executable(uint8_t *mem_block, uint32_t mem_size) {
76
+ if (mprotect(mem_block, mem_size, PROT_READ | PROT_EXEC)) {
77
+ fprintf(stderr, "Couldn't make JIT page (%p) executable, errno: %s", (void *)mem_block, strerror(errno));
78
+ abort();
79
+ }
80
+ }
81
+
82
+ #if defined(MAP_FIXED_NOREPLACE) && defined(_SC_PAGESIZE)
83
+ // Align the current write position to a multiple of bytes
84
+ static uint8_t *align_ptr(uint8_t *ptr, uint32_t multiple)
85
+ {
86
+ // Compute the pointer modulo the given alignment boundary
87
+ uint32_t rem = ((uint32_t)(uintptr_t)ptr) % multiple;
88
+
89
+ // If the pointer is already aligned, stop
90
+ if (rem == 0)
91
+ return ptr;
92
+
93
+ // Pad the pointer by the necessary amount to align it
94
+ uint32_t pad = multiple - rem;
95
+
96
+ return ptr + pad;
97
+ }
98
+ #endif
99
+
100
+ // Allocate a block of executable memory
101
+ uint8_t *rb_yjit_alloc_exec_mem(uint32_t mem_size) {
102
+ #ifndef _WIN32
103
+ uint8_t *mem_block;
104
+
105
+ // On Linux
106
+ #if defined(MAP_FIXED_NOREPLACE) && defined(_SC_PAGESIZE)
107
+ // Align the requested address to page size
108
+ uint32_t page_size = (uint32_t)sysconf(_SC_PAGESIZE);
109
+ uint8_t *req_addr = align_ptr((uint8_t*)&rb_yjit_alloc_exec_mem, page_size);
110
+
111
+ do {
112
+ // Try to map a chunk of memory as executable
113
+ mem_block = (uint8_t*)mmap(
114
+ (void*)req_addr,
115
+ mem_size,
116
+ PROT_READ | PROT_EXEC,
117
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE,
118
+ -1,
119
+ 0
120
+ );
121
+
122
+ // If we succeeded, stop
123
+ if (mem_block != MAP_FAILED) {
124
+ break;
125
+ }
126
+
127
+ // +4MB
128
+ req_addr += 4 * 1024 * 1024;
129
+ } while (req_addr < (uint8_t*)&rb_yjit_alloc_exec_mem + INT32_MAX);
130
+
131
+ // On MacOS and other platforms
132
+ #else
133
+ // Try to map a chunk of memory as executable
134
+ mem_block = (uint8_t*)mmap(
135
+ (void*)yjit_alloc_exec_mem,
136
+ mem_size,
137
+ PROT_READ | PROT_EXEC,
138
+ MAP_PRIVATE | MAP_ANONYMOUS,
139
+ -1,
140
+ 0
141
+ );
142
+ #endif
143
+
144
+ // Fallback
145
+ if (mem_block == MAP_FAILED) {
146
+ // Try again without the address hint (e.g., valgrind)
147
+ mem_block = (uint8_t*)mmap(
148
+ NULL,
149
+ mem_size,
150
+ PROT_READ | PROT_EXEC,
151
+ MAP_PRIVATE | MAP_ANONYMOUS,
152
+ -1,
153
+ 0
154
+ );
155
+ }
156
+
157
+ // Check that the memory mapping was successful
158
+ if (mem_block == MAP_FAILED) {
159
+ perror("mmap call failed");
160
+ exit(-1);
161
+ }
162
+
163
+ // Fill the executable memory with PUSH DS (0x1E) so that
164
+ // executing uninitialized memory will fault with #UD in
165
+ // 64-bit mode.
166
+ yjit_mark_all_writable(mem_block, mem_size);
167
+ memset(mem_block, 0x1E, mem_size);
168
+ yjit_mark_all_executable(mem_block, mem_size);
169
+
170
+ return mem_block;
171
+ #else
172
+ // Windows not supported for now
173
+ return NULL;
174
+ #endif
175
+ }
176
+ */
177
+
66
178
uint8_t *
67
179
rb_yjit_alloc_exec_mem (uint32_t mem_size )
68
180
{
0 commit comments