Created
August 23, 2021 17:02
-
-
Save ryancdotorg/07a4aa0309d9452f079dfa0447da48a6 to your computer and use it in GitHub Desktop.
A simple command line random number generator that can compile on x86_64 without libc
This file contains 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
// gcc -Os -DNO_LIBC -fno-builtin -static -nostdlib -fomit-frame-pointer rand.c -o rand | |
// gcc -O3 rand.c -o rand | |
#define _GNU_SOURCE | |
#include <unistd.h> | |
#include <sys/syscall.h> | |
#include <sys/types.h> | |
#include <sys/random.h> | |
#include <inttypes.h> | |
#ifdef NO_LIBC | |
static inline void __attribute__ ((noreturn)) _sys_exit(int n) { | |
register int rdi asm("rdi") = n; | |
asm volatile( | |
"xor %%eax, %%eax\n" | |
"add %0, %%al\n" | |
"syscall\n" | |
: | |
: "n"(SYS_exit), "r"(rdi) | |
: "rax", "rcx", "r11", "memory" | |
); | |
} | |
static ssize_t _sys_write(int _fd, const void *_buf, size_t _count) { | |
register int ret asm("rax") = 0; | |
register int fd asm("rdi") = _fd; | |
register const void *buf asm("rsi") = _buf; | |
register size_t count asm("rdx") = _count; | |
asm volatile( | |
"xor %%eax, %%eax\n" | |
"add %1, %%al\n" | |
"syscall\n" | |
: "=r"(ret) | |
: "n"(SYS_write), "r"(fd), "r"(buf), "r"(count) | |
: "rcx", "r11", "memory" | |
); | |
return ret; | |
} | |
static ssize_t _sys_getrandom(void *_buf, size_t _buflen, unsigned int _flags) { | |
register ssize_t ret asm("rax"); | |
register void *buf asm("rdi") = _buf; | |
register size_t buflen asm("rsi") = _buflen; | |
register unsigned int flags asm("rdx") = flags; | |
asm volatile( | |
"xor %%eax, %%eax\n" | |
"add %1, %%ax\n" | |
"syscall\n" | |
: "=r"(ret) | |
: "n"(SYS_getrandom), "r"(buf), "r"(buflen), "r"(flags) | |
: "rcx", "r11" | |
); | |
return ret; | |
} | |
#define _write _sys_write | |
#define _getrandom _sys_getrandom | |
#else | |
#define _write write | |
#define _getrandom getrandom | |
#endif | |
static uint64_t randint(uint64_t min, uint64_t max) { | |
uint64_t result, range, mod, top = 0xffffffffffffffffULL; | |
range = (max - min) + 1; | |
mod = top % range; | |
if (mod != range - 1) top -= mod; | |
do { | |
_getrandom(&result, sizeof(result), 0); | |
} while (result > top); | |
if (range) result = min + result % range; | |
return result; | |
} | |
static void write_u64(int fd, uint64_t n) { | |
char buf[32]; | |
char c; | |
int p = sizeof(buf) - 1; | |
buf[p--] = '\n'; | |
do { | |
buf[p--] = '0' + (n % 10); | |
n /= 10; | |
} while (n > 0); | |
int len = (sizeof(buf) - p) - 1; | |
_write(fd, buf + p + 1, len); | |
} | |
static int parse_u64(char *s, uint64_t *n) { | |
*n = 0; | |
char d; | |
int p = 0; | |
for (;;) { | |
d = s[p++]; | |
#if 1 | |
if (d == 0) { | |
return 0; | |
} else if (d >= '0' && d <= '9') { | |
d -= '0'; | |
} else { | |
return -1; | |
} | |
#else | |
switch (s[p]) { | |
case '0': d = 0; break; case '1': d = 1; break; | |
case '2': d = 2; break; case '3': d = 3; break; | |
case '4': d = 4; break; case '5': d = 5; break; | |
case '6': d = 6; break; case '7': d = 7; break; | |
case '8': d = 8; break; case '9': d = 9; break; | |
case '\0': return 0; | |
default: return -1; | |
} | |
#endif | |
if (*n > 1844674407370955161ULL) { | |
return -1; | |
} else if (*n == 1844674407370955161ULL && d > 5) { | |
return -1; | |
} | |
*n *= 10ULL; | |
*n += d; | |
} | |
} | |
int __attribute__ ((noinline)) main(int argc, char *argv[]) { | |
uint64_t x, min = 0, max; | |
if (argc == 1) { | |
max = 32767; | |
} else if (argc == 2) { | |
parse_u64(argv[1], &max); | |
} else if (argc == 3) { | |
parse_u64(argv[1], &min); | |
parse_u64(argv[2], &max); | |
} else { | |
return -1; | |
} | |
x = randint(min, max); | |
write_u64(1, x); | |
return 0; | |
} | |
#ifdef NO_LIBC | |
// minimal entry point | |
void _start() { | |
int argc; char **argv; | |
asm volatile( | |
"mov 0(%%rsp), %0\n" | |
"mov %%rsp, %1\n" | |
"add $8, %1\n" | |
: "=r"(argc), "=r"(argv) :: "memory" | |
); | |
_sys_exit(main(argc, argv)); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment