Last active
July 9, 2025 01:26
-
-
Save rrampage/8d1d2d7ec73ff164e589ae91815fbfdb to your computer and use it in GitHub Desktop.
JIT calculator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// as -o /tmp/calc.o calc.S && ld -s -o /tmp/calc /tmp/calc.o && strip --strip-section-headers /tmp/calc | |
.equ SYS_MEMFD_CREATE, 279 | |
.equ SYS_FTRUNCATE, 46 | |
.equ SYS_MMAP, 222 | |
.equ SYS_READ, 63 | |
.equ SYS_WRITE, 64 | |
.equ SYS_EXIT, 93 | |
.equ BUF_SIZE, 64 | |
.equ PAGE_SIZE, 4096 | |
.equ PROT_READ, 1 | |
.equ PROT_WRITE, 2 | |
.equ PROT_EXEC, 4 | |
.equ MAP_SHARED, 1 | |
.equ STDIN, 0 | |
.equ STDOUT, 1 | |
.section .rodata | |
jit_buf: .ascii "jit_buf" | |
.bss | |
buffer: .space BUF_SIZE | |
output_buffer: .space 16 | |
.text | |
.global _start | |
//brk_val: .word 0xd4200000 | |
// mov_x0_0: .word 0xd2800000 | |
// mov_x1_2: .word 0xd2800041 | |
mul_x0_2: .word 0x9b017c00 // ascii 42 | |
add_x0_1: .word 0x91000400 // ascii 43 | |
// NOP | |
nop_0: .word 0xd503201f // ignore | |
sub_x0_1: .word 0xd1000400 // ascii 45 | |
// NOP | |
nop_1: .word 0xd503201f // ignore | |
sdiv_x0_2: .word 0x9ac10c00 // ascii 47 | |
//mov_x8_93: .word 0xd2800ba8 | |
//svc_0: .word 0xd4000001 | |
ret_val: .word 0xd65f03c0 | |
_start: | |
// memfd_create | |
adr x0, jit_buf | |
mov x8, #SYS_MEMFD_CREATE | |
svc #0 | |
cmp x0, #0 | |
blt exit | |
mov x19, x0 // save fd | |
mov x1, #PAGE_SIZE | |
mov x8, #SYS_FTRUNCATE | |
svc #0 | |
cmp x0, #0 | |
blt exit | |
// syscall6(SYS_mmap, NULL, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); | |
mov x0, #0 | |
// mov x1, #PAGE_SIZE | |
mov x2, #(PROT_READ | PROT_WRITE) | |
mov x3, #MAP_SHARED | |
mov x4, x19 | |
mov x5, #0 | |
mov x8, #SYS_MMAP | |
svc #0 | |
cmp x0, #0 | |
blt exit | |
mov x20, x0 // rw mapping | |
mov x0, #0 | |
// mov x1, #PAGE_SIZE | |
mov x2, #(PROT_READ | PROT_EXEC) | |
mov x3, #MAP_SHARED | |
// mov x4, x19 | |
// mov x5, #0 | |
// mov x8, #SYS_MMAP | |
svc #0 | |
cmp x0, #0 | |
blt exit | |
mov x21, x0 // rx mapping | |
// read | |
mov x8, #SYS_READ | |
mov x0, #STDIN | |
adr x1, buffer | |
mov x2, #BUF_SIZE | |
svc #0 | |
cmp x0, #0 | |
blt exit | |
mov x22, x0 // nread | |
// jit buffer write | |
mov x0, #0 | |
mov x1, #0 | |
adr x4, buffer | |
// Read the rest of string and write instructions | |
parse_input: | |
cmp x1, x22 | |
b.ge done | |
ldrb w3, [x4, x1] | |
add x1, x1, #1 | |
subs w6, w3, #'*' // sub 42 and jump to correct instruction | |
b.mi parse_input | |
cmp w6, 6 | |
b.ge parse_input | |
adr x5, mul_x0_2 | |
lsl x6, x6, 2 | |
ldr x2, [x5, x6] | |
str x2, [x20, x0] | |
add x0, x0, #4 | |
b parse_input | |
done: | |
ldr w2, ret_val | |
str w2, [x20, x0] | |
mov x0, #0 | |
mov x1, #2 | |
blr x21 | |
// Print output to stdout | |
mov x10, x0 | |
mov x6, #10 // Constant 10 for div | |
mov x2, #14 // i=14 | |
adr x1, output_buffer | |
mov w3, #'\n' | |
strb w3, [x1, 15] | |
clz x5, x0 | |
cmp x5, #0 | |
b.gt int_loop | |
mov x7, #1 // sign | |
sub x10, xzr, x10 // negated number | |
int_loop: | |
sdiv x11, x10, x6 // div by 10 | |
msub x3, x11, x6, x10 // modulo 10 | |
add x3, x3, #'0' | |
strb w3, [x1, x2] | |
mov x10, x11 | |
sub x2, x2, #1 | |
cmp x10, #0 | |
b.gt int_loop | |
cmp x7, #1 | |
b.ne rest | |
mov w3, #'-' | |
strb w3, [x1, x2] | |
sub x2, x2, #1 | |
rest: | |
mov x8, #SYS_WRITE | |
mov x0, #STDOUT | |
add x1, x1, x2 | |
sub x2, xzr, x2 | |
add x2, x2, #16 | |
svc #0 | |
exit: | |
mov w8, 93 | |
svc #0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Compiled with: | |
gcc -s -O3 -ffreestanding -nostdlib -nostartfiles -fno-stack-protector -Wl,--entry=_start -Wl,--gc-sections -Wl,-z,now -nostdinc -static -o cjit jit_calc.c | |
*/ | |
typedef unsigned long long size_t; | |
typedef unsigned char u8; | |
typedef unsigned int u32; | |
#define NULL 0 | |
#define BUF_SIZE 64 | |
#define SYS_memfd_create 279 | |
#define SYS_ftruncate 46 | |
#define SYS_mmap 222 | |
#define SYS_read 63 | |
#define SYS_exit 93 | |
#define PROT_READ 1 | |
#define PROT_WRITE 2 | |
#define PROT_EXEC 4 | |
#define MAP_SHARED 1 | |
#define syscall1(num, arg1) \ | |
({ \ | |
register long _num __asm__ ("x8") = (num); \ | |
register long _arg1 __asm__ ("x0") = (long)(arg1); \ | |
\ | |
__asm__ volatile ( \ | |
"svc #0\n" \ | |
: "=r"(_arg1) \ | |
: "r"(_arg1), \ | |
"r"(_num) \ | |
: "memory", "cc" \ | |
); \ | |
_arg1; \ | |
}) | |
#define syscall3(num, arg1, arg2, arg3) \ | |
({ \ | |
register long _num __asm__ ("x8") = (num); \ | |
register long _arg1 __asm__ ("x0") = (long)(arg1); \ | |
register long _arg2 __asm__ ("x1") = (long)(arg2); \ | |
register long _arg3 __asm__ ("x2") = (long)(arg3); \ | |
\ | |
__asm__ volatile ( \ | |
"svc #0\n" \ | |
: "=r" (_arg1) \ | |
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_num) \ | |
: "memory", "cc" \ | |
); \ | |
_arg1; \ | |
}) | |
#define syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ | |
({ \ | |
register long _num __asm__ ("x8") = (num); \ | |
register long _arg1 __asm__ ("x0") = (long)(arg1); \ | |
register long _arg2 __asm__ ("x1") = (long)(arg2); \ | |
register long _arg3 __asm__ ("x2") = (long)(arg3); \ | |
register long _arg4 __asm__ ("x3") = (long)(arg4); \ | |
register long _arg5 __asm__ ("x4") = (long)(arg5); \ | |
register long _arg6 __asm__ ("x5") = (long)(arg6); \ | |
\ | |
__asm__ volatile ( \ | |
"svc #0\n" \ | |
: "=r" (_arg1) \ | |
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | |
"r"(_arg6), "r"(_num) \ | |
: "memory", "cc" \ | |
); \ | |
_arg1; \ | |
}) | |
/* | |
Sample strace output: | |
memfd_create("jit_buf", 0) = 3 | |
ftruncate(3, 4096) = 0 | |
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xe56cd91e6000 | |
mmap(NULL, 4096, PROT_READ|PROT_EXEC, MAP_SHARED, 3, 0) = 0xe56cd91e5000 | |
exit(42) | |
*/ | |
#define MOV_X0_0 0xd2800000 | |
#define MOV_X1_2 0xd2800041 | |
#define ADD_X0_X0_1 0x91000400 | |
#define SUB_X0_X0_1 0xd1000400 | |
#define MUL_X0_X0_X1 0x9b017c00 | |
#define SDIV_X0_X0_X1 0x9ac10c00 | |
#define MOV_X8_93 0xd2800ba8 | |
#define SVC_0 0xd4000001 | |
int jit(u32* code, const char* input, int n) { | |
/* | |
ans: x0 | |
mov x0, #0 | |
+: add x0, x0, 1 | |
-: sub x0, x0, 1 | |
*: mul x0, x0, 2 | |
/: div x0, x0, 2 | |
78: d2800000 mov x0, #0x0 // #0 | |
7c: d2800041 mov x1, #0x2 // #2 | |
80: 91000400 add x0, x0, #0x1 | |
84: d1000400 sub x0, x0, #0x1 | |
88: 9b017c00 mul x0, x0, x1 | |
8c: 9ac10c00 sdiv x0, x0, x1 | |
90: d2800ba8 mov x8, #0x5d // #93 | |
94: d4000001 svc #0x0 | |
*/ | |
int i = 0; | |
code[i++] = MOV_X0_0; | |
code[i++] = MOV_X1_2; | |
for (int j = 0; j < n; j++) { | |
char c = input[j]; | |
switch (c) | |
{ | |
case '+': | |
code[i++] = ADD_X0_X0_1; | |
break; | |
case '-': | |
code[i++] = SUB_X0_X0_1; | |
break; | |
case '*': | |
code[i++] = MUL_X0_X0_X1; | |
break; | |
case '/': | |
code[i++] = SDIV_X0_X0_X1; | |
break; | |
default: | |
break; | |
} | |
} | |
// Outputs value of x0 as exit code | |
code[i++] = MOV_X8_93; | |
code[i++] = SVC_0; | |
return i; | |
} | |
void main() { | |
char input[BUF_SIZE]; | |
size_t pagesize = 4096; | |
int fd = syscall1(SYS_memfd_create, "jit_buf"); | |
syscall3(SYS_ftruncate, fd, pagesize, 0); | |
// Create RW and RX mappings | |
u8 *rw = (void*)syscall6(SYS_mmap, NULL, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); | |
void *rx = (void*)syscall6(SYS_mmap, NULL, pagesize, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0); | |
int nread = syscall3(SYS_read, 0, input, BUF_SIZE); | |
if (nread <= 0) { syscall1(SYS_exit, nread);} | |
u32 *code = (u32 *)rw; | |
int code_size = jit(code, input, nread); | |
((void(*)())rx)(); | |
} | |
__attribute__((section(".text.startup"))) void _start(void) { | |
#if defined(__aarch64__) | |
asm volatile ( | |
"mov fp, #0\n\t" | |
"mov lr, #0\n\t" | |
"mov x0, sp\n\t" | |
"and sp, x0, #-16\n\t" | |
"bl %0\n\t" | |
: | |
: [main] "X"(&main) | |
:"x11", "memory" | |
); | |
#else | |
#error "Unsupported architecture" | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment