Line data Source code
1 : #ifndef HEADER_fd_src_ballet_sbpf_fd_sbpf_loader_h
2 : #define HEADER_fd_src_ballet_sbpf_fd_sbpf_loader_h
3 :
4 : /* fd_sbpf_loader prepares an sBPF program for execution. This involves
5 : parsing and dynamic relocation.
6 :
7 : Due to historical reasons, this loader is neither a pure static
8 : linker nor a real dynamic loader. For instance, it will ignore the
9 : program header table and instead load specific sections at predefined
10 : addresses. However, it will perform dynamic relocation. */
11 :
12 : #include "../../util/fd_util_base.h"
13 : #include "../elf/fd_elf64.h"
14 :
15 : /* Error types ********************************************************/
16 :
17 1547 : #define FD_SBPF_PROG_RODATA_ALIGN 8UL
18 :
19 : /* https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/elf_parser/mod.rs#L17 */
20 : #define FD_SBPF_ELF_PARSER_SUCCESS ( 0)
21 240 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_FILE_HEADER (-1)
22 20 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_PROGRAM_HEADER (-2)
23 7 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_SECTION_HEADER (-3)
24 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_STRING (-4)
25 7 : #define FD_SBPF_ELF_PARSER_ERR_STRING_TOO_LONG (-5)
26 153 : #define FD_SBPF_ELF_PARSER_ERR_OUT_OF_BOUNDS (-6)
27 1 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_SIZE (-7)
28 31 : #define FD_SBPF_ELF_PARSER_ERR_OVERLAP (-8)
29 5 : #define FD_SBPF_ELF_PARSER_ERR_SECTION_NOT_IN_ORDER (-9)
30 0 : #define FD_SBPF_ELF_PARSER_ERR_NO_SECTION_NAME_STRING_TABLE (-10)
31 30 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_DYNAMIC_SECTION_TABLE (-11)
32 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_RELOCATION_TABLE (-12)
33 7 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_ALIGNMENT (-13)
34 : #define FD_SBPF_ELF_PARSER_ERR_NO_STRING_TABLE (-14)
35 : #define FD_SBPF_ELF_PARSER_ERR_NO_DYNAMIC_STRING_TABLE (-15)
36 :
37 : /* Map Rust ElfError (elf.rs v0.12.2) to C error codes */
38 : /* https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/elf.rs#L40-L66 */
39 2001635 : #define FD_SBPF_ELF_SUCCESS ( 0)
40 327 : #define FD_SBPF_ELF_ERR_FAILED_TO_PARSE ( -1)
41 12 : #define FD_SBPF_ELF_ERR_ENTRYPOINT_OUT_OF_BOUNDS ( -2)
42 5 : #define FD_SBPF_ELF_ERR_INVALID_ENTRYPOINT ( -3)
43 : #define FD_SBPF_ELF_ERR_FAILED_TO_GET_SECTION ( -4)
44 166 : #define FD_SBPF_ELF_ERR_UNRESOLVED_SYMBOL ( -5)
45 : #define FD_SBPF_ELF_ERR_SECTION_NOT_FOUND ( -6)
46 10 : #define FD_SBPF_ELF_ERR_RELATIVE_JUMP_OUT_OF_BOUNDS ( -7)
47 1 : #define FD_SBPF_ELF_ERR_SYMBOL_HASH_COLLISION ( -8)
48 0 : #define FD_SBPF_ELF_ERR_WRONG_ENDIANNESS ( -9)
49 4 : #define FD_SBPF_ELF_ERR_WRONG_ABI (-10)
50 3 : #define FD_SBPF_ELF_ERR_WRONG_MACHINE (-11)
51 0 : #define FD_SBPF_ELF_ERR_WRONG_CLASS (-12)
52 29 : #define FD_SBPF_ELF_ERR_NOT_ONE_TEXT_SECTION (-13)
53 6 : #define FD_SBPF_ELF_ERR_WRITABLE_SECTION_NOT_SUPPORTED (-14)
54 : #define FD_SBPF_ELF_ERR_ADDRESS_OUTSIDE_LOADABLE_SECTION (-15)
55 4 : #define FD_SBPF_ELF_ERR_INVALID_VIRTUAL_ADDRESS (-16)
56 20 : #define FD_SBPF_ELF_ERR_UNKNOWN_RELOCATION (-17)
57 : #define FD_SBPF_ELF_ERR_FAILED_TO_READ_RELOCATION_INFO (-18)
58 3 : #define FD_SBPF_ELF_ERR_WRONG_TYPE (-19)
59 17 : #define FD_SBPF_ELF_ERR_UNKNOWN_SYMBOL (-20)
60 197 : #define FD_SBPF_ELF_ERR_VALUE_OUT_OF_BOUNDS (-21)
61 374 : #define FD_SBPF_ELF_ERR_UNSUPPORTED_SBPF_VERSION (-22)
62 10 : #define FD_SBPF_ELF_ERR_INVALID_PROGRAM_HEADER (-23)
63 :
64 : /* https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/program.rs */
65 7178 : #define FD_SBPF_VERSION_COUNT (5U)
66 6888 : #define FD_SBPF_V0 (0U)
67 2454678 : #define FD_SBPF_V1 (1U)
68 3720477 : #define FD_SBPF_V2 (2U)
69 473518 : #define FD_SBPF_V3 (3U)
70 : #define FD_SBPF_V4 (4U)
71 373 : #define FD_SBPF_RESERVED (FD_SBPF_VERSION_COUNT)
72 :
73 : /* Hardcoded constant for the murmur3_32 hash of the entrypoint. */
74 1644474 : #define FD_SBPF_ENTRYPOINT_PC (0xb00c380U)
75 4875 : #define FD_SBPF_ENTRYPOINT_HASH (0x71e3cf81U) /* fd_pchash( FD_SBPF_ENTRYPOINT_PC ) */
76 :
77 : #define E_FLAGS_SBPF_V2 (0x20U)
78 :
79 : /* Program struct *****************************************************/
80 :
81 : /* fd_sbpf_calldests is a bit vector of valid call destinations.
82 : Should be configured to fit any possible program counter. The max
83 : program counter is <size of ELF binary> divided by 8. */
84 :
85 : #define SET_NAME fd_sbpf_calldests
86 : #include "../../util/tmpl/fd_set_dynamic.c"
87 :
88 : /* The sbpf program footprint is large when stricter elf headers are
89 : not enabled due to the calldests bitmap being included. So, the
90 : total footprint of the sbpf_program is the size of the sbpf_program
91 : struct plus the calldests bitmap.
92 :
93 : The calldests bitmap is variable with the text_cnt. A loose bound on
94 : the textcnt is the max size of an account / 8. So, the max possible
95 : text_cnt is 1310720. So the footprint of the sbpf_calldests is as
96 : follows:
97 : sizeof(SET_(private_t))-sizeof(SET_(t)) + sizeof(SET_(t))*SET_(private_word_cnt)( max )
98 : private_word_cnt(1310720) = 20480
99 : sizeof(SET_(t)) = 8 (ulong)
100 : sizeof(SET_(private_t)) = 32
101 : */
102 0 : #define FD_SBPF_TEXT_CNT_MAX (FD_RUNTIME_ACC_SZ_MAX / 8UL)
103 : #define FD_SBPF_CALLDESTS_PRIVATE_WORD_CNT ( (FD_SBPF_TEXT_CNT_MAX +63UL)>>6 )
104 : #define FD_SBPF_PROGRAM_FOOTPRINT \
105 : FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_INIT, \
106 : alignof(fd_sbpf_program_t), sizeof(fd_sbpf_program_t) ), \
107 : alignof(fd_sbpf_calldests_private_t), \
108 : sizeof(fd_sbpf_calldests_private_t)-sizeof(ulong) + sizeof(ulong)*FD_SBPF_CALLDESTS_PRIVATE_WORD_CNT ), \
109 : alignof(fd_sbpf_program_t) )
110 :
111 : /* fd_sbpf_syscall_func_t is a callback implementing an sBPF syscall.
112 : vm is a handle to the running VM. Returns 0 on success or an integer
113 : error code on failure.
114 :
115 : IMPORTANT SAFETY TIP! See notes in
116 : flamenco/vm/syscall/fd_vm_syscall.h on what a syscall should expect
117 : to see and expect to return. */
118 :
119 : /* FIXME: THIS BELONGS IN FLAMENCO/VM */
120 :
121 : typedef int
122 : (*fd_sbpf_syscall_func_t)( void * vm,
123 : ulong arg0,
124 : ulong arg1,
125 : ulong arg2,
126 : ulong arg3,
127 : ulong arg4 );
128 :
129 : /* fd_sbpf_syscalls_t maps syscall IDs => a name and a VM specific
130 : context. FIXME: THIS ALSO PROBABLY BELONGS IN FLAMENCO/VM */
131 :
132 7824563 : #define FD_SBPF_SYSCALLS_LG_SLOT_CNT (7)
133 : #define FD_SBPF_SYSCALLS_SLOT_CNT (1UL<<FD_SBPF_SYSCALLS_LG_SLOT_CNT)
134 :
135 : /* The syscalls map keys should technically be of type uint since they are
136 : just murmur32 hashes. However, Agave's BTree allows the full range to be
137 : used as a key [0, UINT_MAX]. So we need to define a wider key type to
138 : allow for a NULL value that is outside this range. We use ulong here. */
139 :
140 : struct fd_sbpf_syscalls {
141 : ulong key; /* Murmur3-32 hash of function name */
142 : fd_sbpf_syscall_func_t func; /* Function pointer */
143 : char const * name; /* Infinite lifetime pointer to function name */
144 : };
145 :
146 : typedef struct fd_sbpf_syscalls fd_sbpf_syscalls_t;
147 :
148 : #define MAP_NAME fd_sbpf_syscalls
149 1579497 : #define MAP_T fd_sbpf_syscalls_t
150 1561802 : #define MAP_HASH_T ulong
151 4564558 : #define MAP_KEY_NULL ULONG_MAX /* Any number greater than UINT_MAX works */
152 2502179 : #define MAP_KEY_INVAL(k) ( k > UINT_MAX ) /* Force keys to uint size */
153 1527351 : #define MAP_KEY_EQUAL(k0,k1) (k0)==(k1)
154 : #define MAP_KEY_EQUAL_IS_SLOW 0
155 1562417 : #define MAP_KEY_HASH(k) (k)
156 : #define MAP_MEMOIZE 0
157 7824563 : #define MAP_LG_SLOT_CNT FD_SBPF_SYSCALLS_LG_SLOT_CNT
158 : #include "../../util/tmpl/fd_map.c"
159 :
160 : #define FD_SBPF_SYSCALLS_FOOTPRINT (sizeof(fd_sbpf_syscalls_t) * (1UL<<FD_SBPF_SYSCALLS_LG_SLOT_CNT))
161 : #define FD_SBPF_SYSCALLS_ALIGN alignof(fd_sbpf_syscalls_t)
162 :
163 : /* fd_sbpf_elf_info_t contains basic information extracted from an ELF
164 : binary. Indicates how much scratch memory and buffer size is required
165 : to fully load the program. */
166 :
167 : struct fd_sbpf_elf_info {
168 : ulong bin_sz; /* size of ELF binary */
169 :
170 : ulong calldests_max; /* Size of calldests set */
171 : uint text_off; /* File offset of .text section (overlaps rodata segment) */
172 : uint text_cnt; /* Instruction count */
173 : ulong text_sz; /* size of text segment. Guaranteed to be <= bin_sz. */
174 :
175 : /* Size of the buffer the loader assembles the program into, computed at
176 : peek. This is exactly the buffer the program cache must allocate:
177 : - strict (v3+): rodata + text segments (text_off + text_sz)
178 : - lenient fast path: the assembled rodata image (highest ro section
179 : end) -- exact size, no scratch buffer needed.
180 : Selected only when the read-only sections already
181 : sit at their file offsets (section address ==
182 : file offset), so the image needs no section
183 : repositioning, only zeroing of the gaps between
184 : and around the read-only slices.
185 : - lenient legacy path: bin_sz -- the loader relocates in place over the
186 : full ELF image (and may read the unused account
187 : tail), so it needs the whole binary plus scratch
188 : fd_sbpf_loader_is_legacy_lenient() (load_buf_sz==bin_sz) identifies the
189 : last case -- the only one that requires a scratch buffer. */
190 : ulong load_buf_sz;
191 :
192 : /* Known section indices
193 : In [-1,USHORT_MAX) where -1 means "not found" */
194 : int shndx_text;
195 : int shndx_symtab;
196 : int shndx_strtab;
197 : int shndx_dyn;
198 : int shndx_dynstr;
199 : int shndx_dynsymtab; /* Section header index of the dynamic symbol table */
200 :
201 : /* Known program header indices (like shndx_*) */
202 : int phndx_dyn;
203 :
204 : /* Dynamic relocation table entries */
205 : uint dt_rel_off; /* File offset of dynamic relocation table */
206 : uint dt_rel_sz; /* Number of dynamic relocation table entries */
207 :
208 : /* SBPF version, SIMD-0161 */
209 : ulong sbpf_version;
210 : };
211 : typedef struct fd_sbpf_elf_info fd_sbpf_elf_info_t;
212 :
213 : /* fd_sbpf_loader_is_legacy_lenient returns 1 iff the program must be loaded via
214 : the legacy lenient path (relocate in place over the full ELF image using a
215 : scratch buffer). This is exactly the case load_buf_sz==bin_sz: strict (v3+)
216 : and lenient-fast loads assemble a smaller, exact-size buffer with no scratch,
217 : while the legacy path needs the whole binary (load_buf_sz==bin_sz) + scratch. */
218 : FD_FN_PURE static inline int
219 4155 : fd_sbpf_loader_is_legacy_lenient( fd_sbpf_elf_info_t const * info ) {
220 4155 : return info->load_buf_sz==info->bin_sz;
221 4155 : }
222 :
223 : /* fd_sbpf_program_t describes a loaded program in memory.
224 :
225 : [rodata,rodata+bin_sz) is an externally allocated buffer holding
226 : the read-only segment to be loaded into the VM. WARNING: The rodata
227 : area required doing load (bin_sz) is larger than the area mapped into
228 : the VM (rodata_sz).
229 :
230 : [text,text+8*text_cnt) is a sub-region of the read-only segment
231 : containing executable code.
232 :
233 : We need to maintain a separate value tracking the entrypoint calldest
234 : because we lay out our calldests in a set instead of a map (like
235 : Agave does), which is more performant but comes with a few footguns.
236 : Since we only store the target PC and not a keypair of <hash, target
237 : PC>, we need to make sure we unregister the correct target PC from
238 : the map. For all other cases besides the b"entrypoint" string, we can
239 : simply check for membership within the calldests set because the
240 : 32-bit murmur3 hash function is bijective, implying key collision iff
241 : value collision. However, the b"entrypoint" string is a special case
242 : because the key is the hardcoded hash of the b"entrypoint" string,
243 : but the value can correspond to any target PC. This means that
244 : someone could register several different target PCs with the same
245 : entrypoint PC, and we cannot figure out which target PC we must
246 : unregister. Additionally, we would not be able to check for
247 : collisions for multiple registered b"entrypoint" strings with
248 : different target PCs.
249 :
250 : Once entry_pc is set, any future calls to set the entry_pc within the
251 : loader will error out with FD_SBPF_ELF_ERR_SYMBOL_HASH_COLLISION. */
252 :
253 : struct __attribute__((aligned(32UL))) fd_sbpf_program {
254 : fd_sbpf_elf_info_t info;
255 :
256 : /* rodata segment to be mapped into VM memory */
257 : void * rodata; /* rodata segment data */
258 : ulong rodata_sz; /* size of read-only data */
259 :
260 : /* text section within rodata segment */
261 : ulong * text;
262 : ulong entry_pc; /* entrypoint PC (at text[ entry_pc ]). ULONG_MAX if not set. */
263 :
264 : /* Bit vector of valid call destinations (bit count is text_cnt). */
265 : void * calldests_shmem;
266 : /* Local join to bit vector of valid call destinations (target PCs) */
267 : fd_sbpf_calldests_t * calldests;
268 : };
269 : typedef struct fd_sbpf_program fd_sbpf_program_t;
270 :
271 : struct fd_sbpf_loader_config {
272 : union {
273 : int elf_deploy_checks;
274 : int reject_broken_elfs;
275 : };
276 : uint sbpf_min_version;
277 : uint sbpf_max_version;
278 : };
279 : typedef struct fd_sbpf_loader_config fd_sbpf_loader_config_t;
280 :
281 : /* Prototypes *********************************************************/
282 :
283 : FD_PROTOTYPES_BEGIN
284 :
285 : /* fd_sbpf_elf_peek partially parses the given ELF file in memory region
286 : [bin,bin+bin_sz) Populates `info`. Returns FD_SBPF_ELF_SUCCESS (0)
287 : on success. On failure, returns a negative FD_SBPF_ELF_ERR_* error
288 : code, and the contents of `info` are unspecified.
289 :
290 : elf_deploy_checks: The Agave ELF loader introduced additional checks
291 : that would fail on (certain) existing mainnet programs. Since it is
292 : impossible to retroactively enforce these checks on already deployed programs,
293 : a guard flag is used to enable these checks only when deploying programs.
294 :
295 : sbpf_min_version, sbpf_max_version: determine the min, max SBPF version
296 : allowed, version is retrieved from the ELF header. See SIMD-0161. */
297 :
298 : int
299 : fd_sbpf_elf_peek( fd_sbpf_elf_info_t * info,
300 : void const * bin,
301 : ulong bin_sz,
302 : fd_sbpf_loader_config_t const * config );
303 :
304 : /* fd_sbpf_program_{align,footprint} return the alignment and size
305 : requirements of the memory region backing the fd_sbpf_program_t
306 : object. */
307 :
308 : FD_FN_CONST ulong
309 : fd_sbpf_program_align( void );
310 :
311 : FD_FN_PURE ulong
312 : fd_sbpf_program_footprint( fd_sbpf_elf_info_t const * info );
313 :
314 : /* fd_sbpf_program_new formats prog_mem to hold an fd_sbpf_program_t.
315 : prog_mem must match footprint requirements of the given elf_info.
316 : elf_info may be deallocated on return.
317 :
318 : rodata is the read-only segment buffer that the program is configured
319 : against and must be valid for the lifetime of the program object. It
320 : should also meet the alignment requirements of the program object.
321 : */
322 :
323 : fd_sbpf_program_t *
324 : fd_sbpf_program_new( void * prog_mem,
325 : fd_sbpf_elf_info_t const * elf_info,
326 : void * rodata );
327 :
328 : /* fd_sbpf_program_load loads an eBPF program for execution.
329 :
330 : prog is a program object allocated with fd_sbpf_program_new and must
331 : match the footprint requirements of this ELF file.
332 :
333 : Initializes and populates the program struct with information about
334 : the program and prepares the read-only segment provided in
335 : fd_sbpf_program_new. This includes performing relocations in the
336 : ELF file and zeroing gaps between rodata sections.
337 :
338 : Memory region [bin,bin+bin_sz) contains the ELF file to be loaded.
339 :
340 : syscalls should be a pointer to a map of registered syscalls and
341 : will be checked against when registering calldests for potential
342 : symbol collisions.
343 :
344 : scratch should be a pointer to a scratch area with size scratch_sz,
345 : used to allocate a temporary buffer for the parsed rodata sections
346 : before copying it back into the rodata. recommended size is bin_sz.
347 :
348 : On success, returns FD_SBPF_ELF_SUCCESS (0).
349 : On error, returns a negative FD_SBPF_ELF_ERR_* code.
350 :
351 : ### Compliance
352 :
353 : As of writing, this loader is conformant with Solana SBPF v0.12.2,
354 : SBPF versions V0, V1, and V2.
355 : */
356 :
357 : int
358 : fd_sbpf_program_load( fd_sbpf_program_t * prog,
359 : void const * bin,
360 : ulong bin_sz,
361 : fd_sbpf_syscalls_t * syscalls,
362 : fd_sbpf_loader_config_t const * config,
363 : void * scratch,
364 : ulong scratch_sz );
365 :
366 : /* fd_sbpf_program_delete destroys the program object and unformats the
367 : memory regions holding it. */
368 :
369 : void *
370 : fd_sbpf_program_delete( fd_sbpf_program_t * program );
371 :
372 : /* SBPF versions and features. This should stay in sync with the macro
373 : definitions in fd_vm_private.h until they are removed (once Agave
374 : cleans up the jump table).
375 : https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/program.rs#L28 */
376 :
377 1853 : #define FD_VM_SBPF_DYNAMIC_STACK_FRAMES_ALIGN (64U)
378 :
379 : /* SIMD-0166 */
380 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L32-L34 */
381 769 : static inline int fd_sbpf_manual_stack_frame_bump_enabled ( ulong v ) { return v==FD_SBPF_V1 || v==FD_SBPF_V2; }
382 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L36-L38 */
383 0 : static inline int fd_sbpf_stack_frame_gaps_enabled ( ulong v ) { return v==FD_SBPF_V0; }
384 :
385 : /* SIMD-0174 */
386 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L41-L43 */
387 0 : static inline int fd_sbpf_enable_pqr_enabled ( ulong v ) { return v==FD_SBPF_V2; }
388 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L45-L47 */
389 0 : static inline int fd_sbpf_explicit_sign_extension_of_results_enabled ( ulong v ) { return v==FD_SBPF_V2; }
390 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L49-L51 */
391 0 : static inline int fd_sbpf_swap_sub_reg_imm_operands_enabled ( ulong v ) { return v==FD_SBPF_V2; }
392 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L53-L55 */
393 0 : static inline int fd_sbpf_disable_neg_enabled ( ulong v ) { return v==FD_SBPF_V2; }
394 :
395 : /* SIMD-0173 */
396 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L58-L60 */
397 1368 : static inline int fd_sbpf_callx_uses_src_reg_enabled ( ulong v ) { return v==FD_SBPF_V2; }
398 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L62-L64 */
399 0 : static inline int fd_sbpf_disable_lddw_enabled ( ulong v ) { return v==FD_SBPF_V2; }
400 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L66-L68 */
401 0 : static inline int fd_sbpf_disable_le_enabled ( ulong v ) { return v==FD_SBPF_V2; }
402 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L70-L72 */
403 0 : static inline int fd_sbpf_move_memory_ix_classes_enabled ( ulong v ) { return v==FD_SBPF_V2; }
404 :
405 : /* SIMD-0178 */
406 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L75-L77 */
407 0 : static inline int fd_sbpf_static_syscalls_enabled ( ulong v ) { return v>=FD_SBPF_V3; }
408 :
409 : /* SIMD-0189 */
410 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L79-L81 */
411 30274 : static inline int fd_sbpf_enable_stricter_elf_headers_enabled ( ulong v ) { return v>=FD_SBPF_V3; }
412 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L83-L85 */
413 0 : static inline int fd_sbpf_enable_lower_rodata_vaddr_enabled ( ulong v ) { return v>=FD_SBPF_V3; }
414 :
415 : /* SIMD-0377 */
416 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L87-L89 */
417 0 : static inline int fd_sbpf_enable_jmp32_enabled ( ulong v ) { return v>=FD_SBPF_V3; }
418 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L91-L93 */
419 1355 : static inline int fd_sbpf_callx_uses_dst_reg_enabled ( ulong v ) { return v>=FD_SBPF_V3; }
420 :
421 : FD_PROTOTYPES_END
422 :
423 : #endif /* HEADER_fd_src_ballet_sbpf_fd_sbpf_loader_h */
|