Line data Source code
1 : #include "fd_vm_syscall.h"
2 :
3 : #include "../../../ballet/base64/fd_base64.h"
4 : #include "../../../ballet/utf8/fd_utf8.h"
5 :
6 : int
7 : fd_vm_syscall_abort( /**/ void * _vm,
8 : FD_PARAM_UNUSED ulong r1,
9 : FD_PARAM_UNUSED ulong r2,
10 : FD_PARAM_UNUSED ulong r3,
11 : FD_PARAM_UNUSED ulong r4,
12 33 : FD_PARAM_UNUSED ulong r5 ) {
13 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/mod.rs#L630 */
14 33 : fd_vm_t * vm = (fd_vm_t *)_vm;
15 33 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_ABORT );
16 33 : return FD_VM_SYSCALL_ERR_ABORT;
17 33 : }
18 :
19 : /* FD_TRANSLATE_STRING returns a read only pointer to the host address of
20 : a valid utf8 string, or it errors.
21 :
22 : Analogous of Agave's translate_string_and_do().
23 : https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/mod.rs#L601
24 :
25 : As of v0.2.6, the only two usages are in syscall panic and syscall log. */
26 512 : #define FD_TRANSLATE_STRING( vm, vaddr, msg_sz ) (__extension__({ \
27 512 : char const * msg = FD_VM_MEM_SLICE_HADDR_LD( vm, vaddr, FD_VM_ALIGN_RUST_U8, msg_sz ); \
28 512 : if( FD_UNLIKELY( !fd_utf8_verify( msg, msg_sz ) ) ) { \
29 3 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_STRING ); \
30 3 : return FD_VM_SYSCALL_ERR_INVALID_STRING; \
31 3 : } \
32 512 : msg; \
33 509 : }))
34 :
35 : int
36 : fd_vm_syscall_sol_panic( /**/ void * _vm,
37 : /**/ ulong file_vaddr,
38 : /**/ ulong file_sz,
39 : /**/ ulong line,
40 : /**/ ulong column,
41 21 : FD_PARAM_UNUSED ulong r5 ) {
42 21 : fd_vm_t * vm = (fd_vm_t *)_vm;
43 :
44 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/mod.rs#L637
45 :
46 : Note: this syscall is not used by the Rust SDK, only by the C SDK.
47 : Rust transforms `panic!()` into a log, followed by an abort.
48 : It's unclear if this syscall actually makes any sense... */
49 21 : FD_VM_CU_UPDATE( vm, file_sz );
50 :
51 : /* Validate string */
52 19 : FD_TRANSLATE_STRING( vm, file_vaddr, file_sz );
53 :
54 : /* Note: we truncate the log, ignoring file, line, column.
55 : As mentioned above, it's unclear if anyone is even using this syscall,
56 : so dealing with the complexity of Agave's log is a waste of time. */
57 0 : (void)line;
58 18 : (void)column;
59 :
60 18 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_PANIC );
61 18 : return FD_VM_SYSCALL_ERR_PANIC;
62 38 : }
63 :
64 : int
65 : fd_vm_syscall_sol_log( /**/ void * _vm,
66 : /**/ ulong msg_vaddr,
67 : /**/ ulong msg_sz,
68 : FD_PARAM_UNUSED ulong r3,
69 : FD_PARAM_UNUSED ulong r4,
70 503 : FD_PARAM_UNUSED ulong r5 ) {
71 503 : fd_vm_t * vm = (fd_vm_t *)_vm;
72 :
73 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L5 */
74 :
75 503 : FD_VM_CU_UPDATE( vm, fd_ulong_max( msg_sz, FD_VM_SYSCALL_BASE_COST ) );
76 :
77 : /* Note: when msg_sz==0, msg can be undefined.
78 : fd_log_collector_program_log() handles it. */
79 493 : const char * buf = FD_TRANSLATE_STRING( vm, msg_vaddr, msg_sz );
80 0 : fd_log_collector_program_log( vm->instr_ctx, buf, msg_sz );
81 :
82 491 : vm->reg[0] = 0UL;
83 491 : return FD_VM_SUCCESS;
84 986 : }
85 :
86 : int
87 : fd_vm_syscall_sol_log_64( void * _vm,
88 : ulong r1,
89 : ulong r2,
90 : ulong r3,
91 : ulong r4,
92 457 : ulong r5 ) {
93 457 : fd_vm_t * vm = (fd_vm_t *)_vm;
94 :
95 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L37 */
96 :
97 457 : FD_VM_CU_UPDATE( vm, FD_VM_LOG_64_UNITS );
98 :
99 : /* Max msg_sz: 46 - 15 + 16*5 = 111 < 127 => we can use printf */
100 0 : fd_log_collector_printf_dangerous_max_127( vm->instr_ctx,
101 455 : "Program log: 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx", r1, r2, r3, r4, r5 );
102 :
103 455 : vm->reg[0] = 0UL;
104 455 : return FD_VM_SUCCESS;
105 457 : }
106 :
107 : int
108 : fd_vm_syscall_sol_log_compute_units( /**/ void * _vm,
109 : FD_PARAM_UNUSED ulong r1,
110 : FD_PARAM_UNUSED ulong r2,
111 : FD_PARAM_UNUSED ulong r3,
112 : FD_PARAM_UNUSED ulong r4,
113 481 : FD_PARAM_UNUSED ulong r5 ) {
114 481 : fd_vm_t * vm = (fd_vm_t *)_vm;
115 :
116 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L60 */
117 :
118 481 : FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
119 :
120 : /* Max msg_sz: 40 - 3 + 20 = 57 < 127 => we can use printf */
121 0 : fd_log_collector_printf_dangerous_max_127( vm->instr_ctx,
122 480 : "Program consumption: %lu units remaining", vm->cu );
123 :
124 480 : vm->reg[0] = 0UL;
125 480 : return FD_VM_SUCCESS;
126 481 : }
127 :
128 : int
129 : fd_vm_syscall_sol_log_pubkey( /**/ void * _vm,
130 : /**/ ulong pubkey_vaddr,
131 : FD_PARAM_UNUSED ulong r2,
132 : FD_PARAM_UNUSED ulong r3,
133 : FD_PARAM_UNUSED ulong r4,
134 141 : FD_PARAM_UNUSED ulong r5 ) {
135 141 : fd_vm_t * vm = (fd_vm_t *)_vm;
136 :
137 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L84 */
138 :
139 141 : FD_VM_CU_UPDATE( vm, FD_VM_LOG_PUBKEY_UNITS );
140 :
141 416 : void const * pubkey = FD_VM_MEM_HADDR_LD( vm, pubkey_vaddr, FD_VM_ALIGN_RUST_PUBKEY, sizeof(fd_pubkey_t) );
142 :
143 0 : char msg[ FD_BASE58_ENCODED_32_SZ ]; ulong msg_sz;
144 416 : if( FD_UNLIKELY( fd_base58_encode_32( pubkey, &msg_sz, msg )==NULL ) ) {
145 0 : return FD_VM_SYSCALL_ERR_INVALID_STRING;
146 0 : }
147 :
148 138 : fd_log_collector_program_log( vm->instr_ctx, msg, msg_sz );
149 :
150 138 : vm->reg[0] = 0UL;
151 138 : return FD_VM_SUCCESS;
152 416 : }
153 :
154 : int
155 : fd_vm_syscall_sol_log_data( /**/ void * _vm,
156 : /**/ ulong slice_vaddr,
157 : /**/ ulong slice_cnt,
158 : FD_PARAM_UNUSED ulong r3,
159 : FD_PARAM_UNUSED ulong r4,
160 169 : FD_PARAM_UNUSED ulong r5 ) {
161 169 : fd_vm_t * vm = (fd_vm_t *)_vm;
162 :
163 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L109
164 :
165 : Note: this is implemented following Agave's perverse behavior.
166 : We need to loop the slice multiple times to match the exact error,
167 : first compute budget, then memory mapping.
168 : And finally, we can loop to log. */
169 :
170 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L121 */
171 :
172 169 : FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
173 :
174 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L123-L128 */
175 :
176 336 : fd_vm_vec_t const * slice = (fd_vm_vec_t const *)FD_VM_MEM_SLICE_HADDR_LD( vm, slice_vaddr, FD_VM_ALIGN_RUST_SLICE_U8_REF,
177 336 : fd_ulong_sat_mul( slice_cnt, sizeof(fd_vm_vec_t) ) );
178 :
179 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L130-L135 */
180 :
181 168 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_mul( FD_VM_SYSCALL_BASE_COST, slice_cnt ) );
182 :
183 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L136-L141 */
184 :
185 4704 : for( ulong i=0UL; i<slice_cnt; i++ ) {
186 4537 : FD_VM_CU_UPDATE( vm, slice[i].len );
187 4536 : }
188 :
189 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L145-L152 */
190 :
191 167 : ulong msg_sz = 14UL; /* "Program data: ", with space */
192 4699 : for( ulong i=0UL; i<slice_cnt; i++ ) {
193 4533 : ulong cur_len = slice[i].len;
194 : /* This fails the syscall in case of memory mapping issues */
195 9065 : FD_VM_MEM_SLICE_HADDR_LD( vm, slice[i].addr, FD_VM_ALIGN_RUST_U8, cur_len );
196 : /* Every buffer will be base64 encoded + space separated */
197 0 : msg_sz += (slice[i].len + 2)/3*4 + (i > 0);
198 9065 : }
199 :
200 : /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L156 */
201 :
202 166 : fd_log_collector_t * log = vm->instr_ctx->runtime->log.log_collector;
203 166 : if( FD_LIKELY( log->disabled ) ) {
204 166 : vm->reg[0] = 0UL;
205 166 : return FD_VM_SUCCESS;
206 166 : }
207 :
208 0 : char msg[ FD_LOG_COLLECTOR_MAX ];
209 0 : ulong bytes_written = fd_log_collector_check_and_truncate( log, msg_sz );
210 0 : if( FD_LIKELY( bytes_written < ULONG_MAX ) ) {
211 0 : fd_memcpy( msg, "Program data: ", 14 );
212 0 : char * buf = msg + 14;
213 :
214 0 : for( ulong i=0UL; i<slice_cnt; i++ ) {
215 0 : ulong cur_len = slice[i].len;
216 0 : void const * bytes = FD_VM_MEM_SLICE_HADDR_LD( vm, slice[i].addr, FD_VM_ALIGN_RUST_U8, cur_len );
217 :
218 0 : if( i ) { *buf = ' '; ++buf; } /* skip first */
219 0 : buf += fd_base64_encode( buf, bytes, cur_len );
220 0 : }
221 0 : FD_TEST( (ulong)(buf-msg)==msg_sz );
222 :
223 0 : fd_log_collector_msg( vm->instr_ctx, msg, msg_sz );
224 0 : }
225 :
226 0 : vm->reg[0] = 0UL;
227 0 : return FD_VM_SUCCESS;
228 0 : }
229 :
230 : int
231 : fd_vm_syscall_sol_alloc_free( /**/ void * _vm,
232 : /**/ ulong sz,
233 : /**/ ulong free_vaddr,
234 : FD_PARAM_UNUSED ulong r3,
235 : FD_PARAM_UNUSED ulong r4,
236 458 : FD_PARAM_UNUSED ulong r5 ) {
237 458 : fd_vm_t * vm = (fd_vm_t *)_vm;
238 :
239 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L666 */
240 :
241 : /* This syscall is ... uh ... problematic. But the community has
242 : already recognized this and deprecated it:
243 :
244 : https://github.com/solana-labs/solana/blob/v1.17.23/sdk/src/feature_set.rs#L846
245 :
246 : Unfortunately, old code never dies so, practically, this will need
247 : to be supported until the heat death of the universe.
248 :
249 : The most serious issue is that there is nothing to stop VM code
250 : making a decision based on the _location_ of the returned
251 : allocation. If different validator implementations use different
252 : allocator algorithms, though each implementation would behave
253 : functionally correct in isolation, the VM code that uses it would
254 : actually break consensus.
255 :
256 : As a result, every validator needs to use a bit-for-bit identical
257 : allocation algorithm. Fortunately, Solana is just using a basic
258 : bump allocator:
259 :
260 : https://github.com/solana-labs/solana/blob/v1.17.23/program-runtime/src/invoke_context.rs#L122-L148
261 :
262 : vm->heap_{sz,max} and the below replicate this exactly.
263 :
264 : Another major issue is that this alloc doesn't always conform
265 : typical malloc/free semantics (e.g. C/C++ requires malloc to have
266 : an alignment safe for primitive types ... 8 for the Solana machine
267 : model). This is clearly to support backward compat with older VM
268 : code (though ideally a malloc syscall should have behaved like ...
269 : well ... malloc from day 1). So the alignment behavior below is a
270 : bug-for-bug replication of that:
271 :
272 : https://github.com/solana-labs/solana/blob/v1.17.23/programs/bpf_loader/src/syscalls/mod.rs#L645-L681
273 : https://github.com/solana-labs/solana/blob/v1.17.23/sdk/program/src/entrypoint.rs#L265-L266
274 :
275 : More generally and already ranted about elsewhere, any code that
276 : uses malloc/free style dynamic allocation is inherently broken. So
277 : this syscall should have never existed in the first place ... it
278 : just feeds the trolls. The above is just additional implementation
279 : horror because people consistent think malloc/free is much simpler
280 : than it actually is. This is also an example of how quickly
281 : mistakes fossilize and become a thorn-in-the-side forever.
282 :
283 : IMPORTANT SAFETY TIP! heap_start must be non zero and both
284 : heap_start and heap_end should have an alignment of at least 8.
285 : This existing runtime policies around heap implicitly satisfy this.
286 :
287 : IMPORTANT SAFETY TIP! The specification for Rust's align_offset
288 : doesn't seem to provide a strong guarantee that it will return the
289 : minimal positive offset necessary to align pointers. It is
290 : possible for a "conforming" Rust compiler to break consensus by
291 : using a different align_offset implementation that aligned pointer
292 : between different compilations of the Solana validator and the
293 : below. */
294 :
295 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L676-L680 */
296 :
297 458 : ulong align = fd_vm_is_check_align_enabled( vm ) ? 8UL : FD_VM_ALIGN_RUST_U8;
298 :
299 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L684
300 : Nothing to do.
301 : TODO: unclear if it throw InstructionError::CallDepth
302 : https://github.com/anza-xyz/agave/blob/v2.0.8/program-runtime/src/invoke_context.rs#L662 */
303 :
304 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L685-L693 */
305 :
306 : /* Non-zero free address implies that this is a free() call. Since
307 : this is a bump allocator, free is a no-op. */
308 458 : if( FD_UNLIKELY( free_vaddr ) ) {
309 4 : vm->reg[0] = 0UL;
310 4 : return FD_VM_SUCCESS;
311 4 : }
312 :
313 :
314 454 : ulong heap_sz = fd_ulong_align_up( vm->heap_sz, align );
315 454 : ulong heap_vaddr = fd_ulong_sat_add ( heap_sz, FD_VM_MEM_MAP_HEAP_REGION_START );
316 454 : /**/ heap_sz = fd_ulong_sat_add ( heap_sz, sz );
317 :
318 454 : if( FD_UNLIKELY( heap_sz > vm->heap_max ) ) { /* Not enough free memory */
319 71 : vm->reg[0] = 0UL;
320 71 : return FD_VM_SUCCESS;
321 71 : }
322 :
323 383 : vm->heap_sz = heap_sz;
324 :
325 383 : vm->reg[0] = heap_vaddr;
326 383 : return FD_VM_SUCCESS;
327 454 : }
328 :
329 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mem_ops.rs#L145 */
330 : int
331 : fd_vm_memmove( fd_vm_t * vm,
332 : ulong dst_vaddr,
333 : ulong src_vaddr,
334 1791 : ulong sz ) {
335 1791 : if( FD_UNLIKELY( !sz ) ) {
336 11 : return FD_VM_SUCCESS;
337 11 : }
338 :
339 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mem_ops.rs#L188-L192 */
340 1780 : fd_vm_haddr_query_t dst_ref_mut_query = {
341 1780 : .vaddr = dst_vaddr,
342 1780 : .align = FD_VM_ALIGN_RUST_U8,
343 1780 : .sz = sz,
344 1780 : .is_slice = 1,
345 1780 : };
346 :
347 1780 : fd_vm_haddr_query_t * queries[] = { &dst_ref_mut_query };
348 1780 : FD_VM_TRANSLATE_MUT( vm, queries );
349 :
350 1754 : void const * src = FD_VM_MEM_HADDR_LD( vm, src_vaddr, FD_VM_ALIGN_RUST_U8, sz );
351 0 : memmove( dst_ref_mut_query.haddr, src, sz );
352 :
353 1720 : return FD_VM_SUCCESS;
354 3474 : }
355 :
356 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mem_ops.rs#L41 */
357 : int
358 : fd_vm_syscall_sol_memmove( /**/ void * _vm,
359 : /**/ ulong dst_vaddr,
360 : /**/ ulong src_vaddr,
361 : /**/ ulong sz,
362 : FD_PARAM_UNUSED ulong r4,
363 193 : FD_PARAM_UNUSED ulong r5 ) {
364 193 : fd_vm_t * vm = (fd_vm_t *)_vm;
365 :
366 193 : FD_VM_CU_MEM_OP_UPDATE( vm, sz );
367 :
368 0 : vm->reg[0] = 0UL;
369 :
370 : /* No overlap check for memmove. */
371 193 : return fd_vm_memmove( vm, dst_vaddr, src_vaddr, sz );
372 193 : }
373 :
374 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mem_ops.rs#L18 */
375 : int
376 : fd_vm_syscall_sol_memcpy( /**/ void * _vm,
377 : /**/ ulong dst_vaddr,
378 : /**/ ulong src_vaddr,
379 : /**/ ulong sz,
380 : FD_PARAM_UNUSED ulong r4,
381 1605 : FD_PARAM_UNUSED ulong r5 ) {
382 1605 : fd_vm_t * vm = (fd_vm_t *)_vm;
383 :
384 1605 : FD_VM_CU_MEM_OP_UPDATE( vm, sz );
385 :
386 0 : vm->reg[0] = 0UL;
387 :
388 : /* Exact same as memmove, except also check overlap.
389 : https://github.com/anza-xyz/agave/blob/v2.2.17/programs/bpf_loader/src/syscalls/mem_ops.rs#L45 */
390 1604 : FD_VM_MEM_CHECK_NON_OVERLAPPING( vm, src_vaddr, sz, dst_vaddr, sz );
391 :
392 1598 : return fd_vm_memmove( vm, dst_vaddr, src_vaddr, sz );
393 1604 : }
394 :
395 : int
396 : fd_vm_syscall_sol_memcmp( /**/ void * _vm,
397 : /**/ ulong m0_vaddr,
398 : /**/ ulong m1_vaddr,
399 : /**/ ulong sz,
400 : /**/ ulong out_vaddr,
401 1653 : FD_PARAM_UNUSED ulong r5 ) {
402 1653 : fd_vm_t * vm = (fd_vm_t *)_vm;
403 1653 : vm->reg[0] = 0UL;
404 :
405 : /* https://github.com/anza-xyz/agave/blob/v2.2.17/programs/bpf_loader/src/syscalls/mem_ops.rs#L84 */
406 :
407 1653 : FD_VM_CU_MEM_OP_UPDATE( vm, sz );
408 :
409 : /* Note: though this behaves like a normal C-style memcmp, we can't
410 : use the compilers / libc memcmp directly because the specification
411 : doesn't provide strong enough guarantees about the return value (it
412 : only promises the sign). */
413 :
414 3301 : uchar const * m0 = (uchar const *)FD_VM_MEM_SLICE_HADDR_LD( vm, m0_vaddr, FD_VM_ALIGN_RUST_U8, sz );
415 3295 : uchar const * m1 = (uchar const *)FD_VM_MEM_SLICE_HADDR_LD( vm, m1_vaddr, FD_VM_ALIGN_RUST_U8, sz );
416 :
417 : /* Silly that this doesn't use r0 to return ... slower, more edge
418 : case, different from libc style memcmp, harder to callers to use,
419 : etc ... probably too late to do anything about it now ... sigh */
420 :
421 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mem_ops.rs#L121-L125 */
422 0 : fd_vm_haddr_query_t cmp_result_ref_mut_query = {
423 3295 : .vaddr = out_vaddr,
424 3295 : .align = FD_VM_ALIGN_RUST_I32,
425 3295 : .sz = 4UL,
426 3295 : .is_slice = 0,
427 3295 : };
428 :
429 3295 : fd_vm_haddr_query_t * queries[] = { &cmp_result_ref_mut_query };
430 3295 : FD_VM_TRANSLATE_MUT( vm, queries );
431 :
432 : /* Aliased slices are equal. */
433 :
434 1646 : if( FD_UNLIKELY( m0==m1 ) ) {
435 7 : FD_STORE( uint, cmp_result_ref_mut_query.haddr, 0U );
436 7 : return FD_VM_SUCCESS;
437 7 : }
438 :
439 : /* Find the difference searching by blocks, then words, then bytes, this way
440 : the search is vectorized.
441 : BLK is 256 because at -O3 gcc unrolls smaller blocks into scalar code instead.
442 :
443 : Alternative considered:
444 :
445 : for( ; i+64UL<=sz; i+=64UL )
446 : if( FD_UNLIKELY( wwv_ne( wwv_ldu( m0+i ), wwv_ldu( m1+i ) ) ) ) break;
447 :
448 : it's more readable but requires more combinations (AVX512, AVX2, ARM in future...),
449 : this is a single version that should apply to all. */
450 :
451 4943 : #define BLK (256UL)
452 :
453 1639 : int out = 0;
454 1639 : ulong i = 0UL;
455 1674 : for( ; i+BLK<=sz; i+=BLK ) {
456 98 : ulong d = 0UL;
457 3234 : for( ulong k=0UL; k<BLK; k+=8UL ) {
458 3136 : d |= fd_ulong_load_8( m0+i+k ) ^ fd_ulong_load_8( m1+i+k );
459 3136 : }
460 98 : if( FD_UNLIKELY( d ) ) {
461 63 : break;
462 63 : }
463 98 : }
464 5748 : for( ; i+8UL<=sz; i+=8UL ) {
465 4875 : if( FD_UNLIKELY( fd_ulong_load_8( m0+i )!=fd_ulong_load_8( m1+i ) ) ) {
466 766 : break;
467 766 : }
468 4875 : }
469 2384 : for( ; i<sz; i++ ) {
470 1511 : int i0 = (int)m0[i];
471 1511 : int i1 = (int)m1[i];
472 1511 : if( i0!=i1 ) {
473 766 : out = i0 - i1;
474 766 : break;
475 766 : }
476 1511 : }
477 :
478 1639 : #undef BLK
479 :
480 1639 : FD_STORE( uint, cmp_result_ref_mut_query.haddr, (uint)out );
481 :
482 1639 : return FD_VM_SUCCESS;
483 1646 : }
484 :
485 : int
486 : fd_vm_syscall_sol_memset( /**/ void * _vm,
487 : /**/ ulong dst_vaddr,
488 : /**/ ulong c,
489 : /**/ ulong sz,
490 : FD_PARAM_UNUSED ulong r4,
491 299 : FD_PARAM_UNUSED ulong r5 ) {
492 299 : fd_vm_t * vm = (fd_vm_t *)_vm;
493 299 : vm->reg[0] = 0UL;
494 :
495 : /* https://github.com/anza-xyz/agave/blob/v2.2.17/programs/bpf_loader/src/syscalls/mem_ops.rs#L142 */
496 :
497 299 : FD_VM_CU_MEM_OP_UPDATE( vm, sz );
498 :
499 299 : if( FD_UNLIKELY( !sz ) ) {
500 1 : return FD_VM_SUCCESS;
501 1 : }
502 :
503 298 : int b = (int)(c & 255UL);
504 :
505 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mem_ops.rs#L155-L159 */
506 298 : fd_vm_haddr_query_t haddr_query = {
507 298 : .vaddr = dst_vaddr,
508 298 : .align = FD_VM_ALIGN_RUST_U8,
509 298 : .sz = sz,
510 298 : .is_slice = 1,
511 298 : };
512 :
513 298 : fd_vm_haddr_query_t * queries[] = { &haddr_query };
514 298 : FD_VM_TRANSLATE_MUT( vm, queries );
515 279 : fd_memset( haddr_query.haddr, b, sz );
516 :
517 279 : return FD_VM_SUCCESS;
518 298 : }
|