├── .gitignore ├── README.md ├── asm ├── .gitignore ├── Makefile ├── arrrrgs.c └── hello.s ├── btree ├── .gitignore ├── Makefile ├── btree.c ├── btree.h └── run ├── chash ├── .gitignore ├── Makefile ├── README.md ├── dist.c ├── dist.h ├── genkeys ├── hash.c ├── murmur.c └── ring.c ├── errno ├── .gitignore ├── Makefile ├── elist ├── errno.c └── mklist ├── fifos ├── .gitignore ├── Makefile ├── fuzz.pl ├── fuzz2.pl ├── io.c ├── io2.c └── size.c ├── flags ├── .gitignore └── flags.c ├── fork └── fork.c ├── fuse └── nullfs │ ├── .gitignore │ ├── Makefile │ └── nullfs.c ├── insist ├── .gitignore ├── Makefile ├── insist.h ├── main.c ├── modern.c ├── modern.s └── traditional.c ├── knave ├── .gitignore ├── Makefile └── knave.c ├── lexer-ll ├── NOTES ├── bql.ll ├── bql.ll.c ├── bql.ll.h ├── bql.regex ├── ll.pl ├── ll1.pl └── main.c ├── malloc ├── .gitignore ├── Makefile ├── fmalloc1.c └── victim.c ├── matrix ├── matrix.pl └── sets ├── mlock ├── .gitignore └── mlock.c ├── nacl ├── .gitignore ├── Makefile ├── common.h ├── decrypt.c ├── decrypt2.c ├── decrypt3.c ├── encrypt.c ├── tweetnacl.c └── tweetnacl.h ├── openssl └── spin ├── rcu ├── .gitignore ├── Makefile ├── api.h ├── lock │ └── main.c ├── plot ├── qs │ └── main.c └── report ├── regm ├── .gitignore ├── Makefile ├── README.md ├── asm.c ├── file.p ├── gencode ├── opcodes.h ├── opcodes.yml ├── pn │ ├── fibonacci.pn │ ├── hello.pn │ ├── numbers.pn │ └── string.pn ├── regm.c └── regm.h ├── ringer ├── Makefile ├── ring.c ├── ring.h ├── ringer.c ├── test └── test.c ├── sedge └── TODO ├── smaps ├── .gitignore ├── Makefile ├── README.md ├── buf.c ├── data │ └── 256k ├── diag ├── fork.c ├── heap.c ├── huge.c ├── lib.c ├── mmap.c ├── null.c └── stack.c ├── zig ├── .gitignore ├── Makefile ├── example.out ├── find-r.c ├── find-r.scm ├── run └── solver.c └── zmq ├── .gitignore ├── Makefile └── req.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.sw[a-p] 2 | *.o 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jameshunt(.us) Research 2 | ======================= 3 | 4 | What is this? 5 | 6 | It's research, yo 7 | 8 | smaps/ 9 | ------ 10 | 11 | Research into the /proc/$PID/smaps file format, what it can tell 12 | us, and how to use it as a component in monitoring and a general 13 | troubleshooting aid. 14 | 15 | [http://jameshunt.us/writings/dist-rrd.html](http://jameshunt.us/writings/dist-rrd.html) 16 | 17 | malloc/ 18 | ------- 19 | 20 | A custom malloc implementation, with an eye towrads stress-testing 21 | software for edge-case failures around memory allocation. 22 | 23 | (article forthcoming...) 24 | 25 | Further Reading 26 | --------------- 27 | 28 | [http://jameshunt.us](http://jameshunt.us) 29 | 30 | 31 | -------------------------------------------------------------------------------- /asm/.gitignore: -------------------------------------------------------------------------------- 1 | /hello 2 | -------------------------------------------------------------------------------- /asm/Makefile: -------------------------------------------------------------------------------- 1 | hello: hello.o 2 | ld -o $@ $+ 3 | 4 | %.o: %.s 5 | nasm -f elf64 -g -F stabs $+ 6 | -------------------------------------------------------------------------------- /asm/arrrrgs.c: -------------------------------------------------------------------------------- 1 | /* 2 | arrrrgs.c - Seeing what functions with long arg lists look like 3 | 4 | This is not meant to be compiled into an executable, just object 5 | code. Try `make arrrrgs.o`. 6 | 7 | To see the assembler code, run `objdump -M intel -d arrrrgs.o` 8 | 9 | 0000000000000000 : 10 | 0: 55 push rbp 11 | 1: 48 89 e5 mov rbp,rsp 12 | 4: 89 7d fc mov DWORD PTR [rbp-0x4],edi 13 | 7: 89 75 f8 mov DWORD PTR [rbp-0x8],esi 14 | a: 89 55 f4 mov DWORD PTR [rbp-0xc],edx 15 | d: 89 4d f0 mov DWORD PTR [rbp-0x10],ecx 16 | 10: 44 89 45 ec mov DWORD PTR [rbp-0x14],r8d 17 | 14: 44 89 4d e8 mov DWORD PTR [rbp-0x18],r9d 18 | 18: 83 45 fc 01 add DWORD PTR [rbp-0x4],0x1 19 | 1c: 83 45 f8 01 add DWORD PTR [rbp-0x8],0x1 20 | 20: 83 45 f4 01 add DWORD PTR [rbp-0xc],0x1 21 | 24: 83 45 f0 01 add DWORD PTR [rbp-0x10],0x1 22 | 28: 83 45 ec 01 add DWORD PTR [rbp-0x14],0x1 23 | 2c: 83 45 e8 01 add DWORD PTR [rbp-0x18],0x1 24 | 30: 83 45 10 01 add DWORD PTR [rbp+0x10],0x1 25 | 34: 83 45 18 01 add DWORD PTR [rbp+0x18],0x1 26 | 38: 83 45 20 01 add DWORD PTR [rbp+0x20],0x1 27 | 3c: 83 45 28 01 add DWORD PTR [rbp+0x28],0x1 28 | 40: 83 45 30 01 add DWORD PTR [rbp+0x30],0x1 29 | 44: 83 45 38 01 add DWORD PTR [rbp+0x38],0x1 30 | 48: b8 00 00 00 00 mov eax,0x0 31 | 4d: 5d pop rbp 32 | 4e: c3 ret 33 | 34 | */ 35 | 36 | int fnargs(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) 37 | { 38 | a++; b++; c++; d++; e++; f++; g++; h++; i++; j++; k++; l++; 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /asm/hello.s: -------------------------------------------------------------------------------- 1 | ; hello.s 2 | ; 21 Aug 2017 - jrh 3 | ; 4 | ; A simple Hello, World! in Intel x86-64 assembly 5 | ; 6 | ; Compile with: 7 | ; nasm -f elf -g -F stabs hello.s 8 | ; ld -o hello hello.o 9 | ; 10 | 11 | section .bss 12 | 13 | section .data 14 | hello_str db "Hello, World!",10 15 | hello_len equ $-hello_str 16 | 17 | section .text 18 | global _start 19 | 20 | _start: 21 | nop ; hi gdb! 22 | 23 | ; write(0, hello_str, hello_len) 24 | mov rax,1 ; system call number 25 | mov rdi,1 ; standard output 26 | mov rsi,hello_str ; buffer to print 27 | mov rdx,hello_len ; bytes to print 28 | syscall 29 | 30 | ; exit(1) 31 | mov rax,60 ; system call number 32 | mov rdi,0 ; exit code 33 | syscall ; trap into kernel mode 34 | -------------------------------------------------------------------------------- /btree/.gitignore: -------------------------------------------------------------------------------- 1 | /btree 2 | -------------------------------------------------------------------------------- /btree/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := -g -Wall -Wpedantic 2 | 3 | btree: btree.o 4 | 5 | clean: 6 | rm -fr btree btree.o btree.dSYM 7 | -------------------------------------------------------------------------------- /btree/btree.c: -------------------------------------------------------------------------------- 1 | #include "btree.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifndef YEARS 9 | # define YEARS 2 10 | #endif 11 | #ifndef SPAN 12 | # define SPAN 30 13 | #endif 14 | 15 | static int 16 | _find(struct btree *bt, uint32_t k) 17 | { 18 | assert(bt != NULL); 19 | 20 | int lo, mid, hi; 21 | 22 | lo = -1; 23 | hi = bt->nkeys; 24 | while (lo + 1 < hi) { 25 | mid = (lo + hi) / 2; 26 | if (bt->keys[mid] == k) return mid; 27 | if (bt->keys[mid] > k) hi = mid; 28 | else lo = mid; 29 | } 30 | return hi; 31 | } 32 | 33 | static int 34 | _isfull(struct btree *bt) 35 | { 36 | assert(bt != NULL); 37 | return bt->nkeys == BTREE_N; 38 | } 39 | 40 | static void 41 | _print(struct btree *bt, int indent) 42 | { 43 | int i; 44 | 45 | assert(bt != NULL); 46 | assert(indent >= 0); 47 | 48 | fprintf(stderr, "%*s[btree %p // %d keys]\n", 49 | indent, "", (void *)bt, bt->nkeys); 50 | 51 | for (i = 0; i < bt->nkeys; i++) { 52 | if (bt->leaf) { 53 | fprintf(stderr, "%*s[%03d] % 10d (= %lu)\n", 54 | indent + 2, "", i, bt->keys[i], bt->vals[i].data); 55 | } else { 56 | fprintf(stderr, "%*s[%03d] % 10d (%p) -->\n", 57 | indent + 2, "", i, bt->keys[i], (void *)bt->vals[i].child); 58 | _print(bt->vals[i].child, indent + 8); 59 | } 60 | 61 | } 62 | if (bt->leaf) { 63 | fprintf(stderr, "%*s[%03d] ~ (= %lu)\n", 64 | indent + 2, "", i, bt->vals[bt->nkeys].data); 65 | } else { 66 | fprintf(stderr, "%*s[%03d] ~ (%p) -->\n", 67 | indent + 2, "", i, (void *)bt->vals[bt->nkeys].child); 68 | _print(bt->vals[bt->nkeys].child, indent + 8); 69 | } 70 | } 71 | 72 | void 73 | btree_print(struct btree *bt) 74 | { 75 | _print(bt, 0); 76 | } 77 | 78 | struct btree * 79 | btree_new() 80 | { 81 | struct btree * bt = calloc(1, sizeof(struct btree)); 82 | assert(bt != NULL); 83 | 84 | bt->leaf = 1; 85 | return bt; 86 | } 87 | 88 | static void 89 | _divide(struct btree *l, struct btree *r, int mid) 90 | { 91 | assert(l != NULL); 92 | assert(r != NULL); 93 | assert(mid != 0); 94 | assert(l->nkeys >= mid); 95 | 96 | r->nkeys = l->nkeys - mid - 1; 97 | l->nkeys = mid; 98 | 99 | memmove(r->keys, &l->keys[mid + 1], sizeof(uint32_t) * r->nkeys ); 100 | memmove(r->vals, &l->vals[mid + 1], sizeof(void *) * (r->nkeys + 1)); 101 | 102 | return; 103 | /* optional */ 104 | memset(&r->keys[r->nkeys], 0, BTREE_N - r->nkeys ); 105 | memset(&r->vals[r->nkeys], 0, BTREE_N - r->nkeys + 1); 106 | } 107 | 108 | static void 109 | _shiftr(struct btree *b, int n) 110 | { 111 | memmove(&b->keys[n + 1], &b->keys[n], sizeof(uint32_t) * (b->nkeys - n)); 112 | memmove(&b->vals[n + 2], &b->vals[n + 1], sizeof(void *) * (b->nkeys - n)); 113 | } 114 | 115 | static struct btree * 116 | _clone(struct btree *bt) 117 | { 118 | struct btree *r; 119 | 120 | r = btree_new(); 121 | assert(r); 122 | 123 | r->leaf = bt->leaf; 124 | return r; 125 | } 126 | 127 | static struct btree * 128 | _insert(struct btree *bt, uint32_t key, uint64_t val, uint32_t *median) 129 | { 130 | int i, mid; 131 | struct btree *r; 132 | 133 | i = _find(bt, key); 134 | 135 | if (i < bt->nkeys && bt->keys[i] == key) { 136 | bt->vals[i].data = val; 137 | return NULL; 138 | } 139 | 140 | if (bt->leaf) { 141 | _shiftr(bt, i); 142 | bt->nkeys++; 143 | bt->keys[i] = key; 144 | bt->vals[i].data = val; 145 | 146 | } else { /* insert in child */ 147 | r = _insert(bt->vals[i].child, key, val, median); 148 | 149 | if (r) { 150 | _shiftr(bt, i); 151 | bt->nkeys++; 152 | bt->keys[i] = *median; 153 | bt->vals[i+1].child = r; 154 | } 155 | } 156 | 157 | /* split the node now, if it is full, to save complexity */ 158 | if (_isfull(bt)) { 159 | mid = bt->nkeys * BTREE_S / 100; 160 | *median = bt->keys[mid]; 161 | 162 | r = _clone(bt); 163 | _divide(bt, r, mid); 164 | return r; 165 | } 166 | 167 | return NULL; 168 | } 169 | 170 | int 171 | btree_insert(struct btree *bt, uint32_t key, uint64_t val) 172 | { 173 | struct btree *l, *r; 174 | uint32_t m; 175 | 176 | assert(bt != NULL); 177 | 178 | r = _insert(bt, key, val, &m); 179 | if (r) { 180 | /* "pivot" root to the left */ 181 | l = btree_new(); 182 | memmove(l, bt, sizeof(*bt)); 183 | 184 | /* re-initialize root as [ l . m . r ] */ 185 | bt->nkeys = 1; 186 | bt->leaf = 0; 187 | bt->vals[0].child = l; 188 | bt->keys[0] = m; 189 | bt->vals[1].child = r; 190 | } 191 | 192 | return 0; 193 | } 194 | 195 | struct analysis { 196 | int nodes; 197 | int set; 198 | int depth; 199 | }; 200 | 201 | static void 202 | _analyze(struct btree *bt, struct analysis *a) 203 | { 204 | int i; 205 | 206 | assert(bt != NULL); 207 | assert(a != NULL); 208 | 209 | a->nodes += 1; 210 | a->set += bt->nkeys + 1; 211 | 212 | if (!bt->leaf) { 213 | for (i = 0; i <= bt->nkeys; i++) 214 | _analyze(bt->vals[i].child, a); 215 | } 216 | } 217 | 218 | static void 219 | btree_analyze(struct btree *bt) 220 | { 221 | struct analysis a; 222 | double size; 223 | const char *unit; 224 | 225 | assert(bt != NULL); 226 | 227 | a.nodes = a.set = 0; 228 | _analyze(bt, &a); 229 | 230 | assert(a.nodes > 0); 231 | assert(a.set >= 0); 232 | 233 | a.depth = 0; 234 | while (bt && !bt->leaf) { 235 | a.depth++; 236 | bt = bt->vals[0].child; 237 | } 238 | 239 | fprintf(stderr, "N=%d, SFF=%0.2f, YEARS=%d, MIN=%d\n", BTREE_N, BTREE_S / 100.0, YEARS, SPAN); 240 | fprintf(stderr, "%d keys / %d nodes / %d levels\n", a.set, a.nodes, a.depth); 241 | fprintf(stderr, "%lu bytes per node\n", sizeof(struct btree)); 242 | fprintf(stderr, "%0.3f%% slots filled\n", a.set * 100.0 / (a.nodes * BTREE_N)); 243 | 244 | size = a.nodes * sizeof(struct btree); 245 | unit = ""; 246 | 247 | fprintf(stderr, "%0.1f bytes (overhead) per key\n", size / a.set); 248 | 249 | if (size > 1024 * 1024 * 1024) { 250 | size /= 1024 * 1024 * 1024; 251 | unit = "G"; 252 | } 253 | if (size > 1024 * 1024) { 254 | size /= 1024 * 1024; 255 | unit = "M"; 256 | } 257 | if (size > 1024) { 258 | size /= 1024; 259 | unit = "K"; 260 | } 261 | 262 | fprintf(stderr, "%0.1lf %sB\n", size, unit); 263 | fprintf(stderr, "\n"); 264 | } 265 | 266 | 267 | 268 | #include 269 | 270 | int 271 | main(int argc, char **argv) 272 | { 273 | uint32_t ts; 274 | unsigned int i; 275 | struct btree *bt; 276 | 277 | bt = btree_new(); 278 | 279 | for (i = 0; i < YEARS * 365U * 86400U; i += SPAN * 60) { 280 | ts = 1234567890 + i; 281 | if (ts % 1000000 == 0) fprintf(stderr, "%d\n", ts); 282 | btree_insert(bt, ts, ts); 283 | } 284 | btree_analyze(bt); 285 | 286 | return 0; 287 | } 288 | -------------------------------------------------------------------------------- /btree/btree.h: -------------------------------------------------------------------------------- 1 | #ifndef BTREE_H 2 | #define BTREE_H 3 | 4 | #include 5 | 6 | #ifndef BTREE_N 7 | # define BTREE_N 340 8 | #endif 9 | 10 | #ifndef BTREE_S 11 | # define BTREE_S 75 12 | #endif 13 | 14 | /* NOTE: this btree structure is not suitable 15 | for writing to disk and then mmap()-ing 16 | back in; it is just for exploration. 17 | */ 18 | struct btree { 19 | int nkeys; 20 | int leaf; 21 | uint32_t keys[BTREE_N]; 22 | union { 23 | uint64_t data; 24 | struct btree *child; 25 | } vals[BTREE_N + 1]; 26 | }; 27 | 28 | struct btree * 29 | btree_new(); 30 | 31 | int 32 | btree_insert(struct btree *bt, uint32_t key, uint64_t val); 33 | 34 | void * 35 | btree_lookup(struct btree *bt, uint32_t key); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /btree/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while [[ $# != 0 ]]; do 4 | make CFLAGS="-DBTREE_S=$1 -DYEARS=${YEARS:-2} -DSPAN=${SPAN:-30}" clean btree && ./btree 5 | shift 6 | done 7 | -------------------------------------------------------------------------------- /chash/.gitignore: -------------------------------------------------------------------------------- 1 | hash 2 | ring 3 | -------------------------------------------------------------------------------- /chash/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := -g -Wall 2 | LDLIBS := -lvigor 3 | 4 | all: hash ring 5 | hash: hash.o 6 | ring: ring.o dist.o murmur.o 7 | 8 | example: hash 9 | @./hash $$(/bin/bash -c 'echo host0{1,2}.example.com:{cpu,memory,load} www.example.com:requests_per_second') 10 | -------------------------------------------------------------------------------- /chash/README.md: -------------------------------------------------------------------------------- 1 | chash - jameshunt(.us) Research 2 | =============================== 3 | 4 | This is **DRAFT** research. The blog post is published (but not 5 | syndicated). Send comments to [feedback@jameshunt.us](mailto:feedback@jameshunt.us) 6 | 7 | Research into (consistent) hashing techniques and methodologies. 8 | 9 | [http://jameshunt.us/writings/dist-rrd.html](http://jameshunt.us/writings/dist-rrd.html) 10 | 11 | Further Reading 12 | --------------- 13 | 14 | [http://jameshunt.us](http://jameshunt.us) 15 | 16 | 17 | -------------------------------------------------------------------------------- /chash/dist.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "dist.h" 5 | 6 | static uint64_t s_node_key(node_t *n, unsigned int i) 7 | { 8 | char *k = string("%lu-%s", i, n); 9 | uint64_t h = murmur64a(k, strlen(k), 0); 10 | free(k); 11 | return h; 12 | } 13 | 14 | static int s_sort_vnodes(const void *a_, const void *b_) 15 | { 16 | uint64_t a = ((const vnode_t *)a_)->key; 17 | uint64_t b = ((const vnode_t *)b_)->key; 18 | return a == b ? 0 : a > b ? 1 : -1; 19 | } 20 | 21 | int ring_init(ring_t* ring, node_t *nodes, unsigned int n) 22 | { 23 | assert(ring != NULL); 24 | assert(nodes != NULL); 25 | assert(n != 0); 26 | 27 | unsigned int i, j, k; 28 | 29 | ring->len = 0; 30 | for (i = 0; i < n; i++) 31 | ring->len += ring->spread * nodes[i].weight; 32 | 33 | ring->vnodes = calloc(ring->len, sizeof(vnode_t)); 34 | assert(ring->vnodes != NULL); 35 | for (i = k = 0; i < n && k < ring->len; i++) { 36 | nodes[i].u = 0; 37 | for (j = 0; j < ring->spread * nodes[i].weight; j++, k++) { 38 | ring->vnodes[k].node = &nodes[i]; 39 | ring->vnodes[k].key = s_node_key(&nodes[i], j); 40 | } 41 | } 42 | 43 | qsort(ring->vnodes, ring->len, sizeof(vnode_t), s_sort_vnodes); 44 | 45 | return 0; 46 | } 47 | 48 | node_t* lookup(ring_t *ring, const char *key) 49 | { 50 | uint64_t h = murmur64a(key, strlen(key), 0); 51 | if (h > ring->vnodes[ring->len - 1].key) 52 | return ring->vnodes[0].node; 53 | 54 | unsigned int i; 55 | for (i = 0; i < ring->len; i++) 56 | if (h <= ring->vnodes[i].key) 57 | return ring->vnodes[i].node; 58 | 59 | return NULL; 60 | } 61 | -------------------------------------------------------------------------------- /chash/dist.h: -------------------------------------------------------------------------------- 1 | #ifndef DIST_H 2 | #define DIST_H 3 | 4 | #include 5 | 6 | typedef struct { 7 | const char *name; 8 | uint8_t weight; 9 | 10 | uint32_t u; /* only used for analysis */ 11 | } node_t; 12 | 13 | typedef struct { 14 | node_t *node; 15 | uint64_t key; 16 | } vnode_t; 17 | 18 | typedef struct { 19 | unsigned int spread; /* how many vnodes per weighting? */ 20 | unsigned int len; 21 | vnode_t *vnodes; 22 | } ring_t; 23 | 24 | uint64_t murmur64a(const void *key, unsigned int len, unsigned int seed); 25 | uint64_t murmur64b(const void *key, unsigned int len, unsigned int seed); 26 | 27 | int ring_init(ring_t* ring, node_t *nodes, unsigned int n); 28 | node_t* lookup(ring_t *ring, const char *key); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /chash/genkeys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | my @types = qw/web db asset cache mon/; 4 | my @checks = qw/memory load cpu disk procs forks swap syslog ntp ssh logs authlog dmesg/; 5 | 6 | my $MAX = shift @ARGV || 16; 7 | 8 | my $n = 0; 9 | for (;;) { 10 | $n++; 11 | for my $t (@types) { 12 | for my $c (@checks) { 13 | printf "%s%02i.example.com:%s\n", $t, $n, $c; 14 | exit 0 unless --$MAX; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /chash/hash.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned long 4 | hash(unsigned char *str) 5 | { 6 | unsigned long hash = 5381; 7 | int c; 8 | 9 | while ((c = *str++)) 10 | hash = ((hash << 5) + hash) + c; 11 | 12 | return hash; 13 | } 14 | 15 | int main(int argc, char **argv) 16 | { 17 | int i; 18 | for (i = 1; i < argc; i++) 19 | printf(" \"%s\" = %lu\n", argv[i], hash((unsigned char*)argv[i]) & 0xff); 20 | printf("\n\n"); 21 | for (i = 1; i < argc; i++) 22 | printf(" L(%s) = %lu mod %i = %lu\n", argv[i], 23 | hash((unsigned char*)argv[i]) & 0xff, 3, 24 | (hash((unsigned char*)argv[i]) & 0xff) % 3); 25 | printf("\n\n"); 26 | for (i = 1; i < argc; i++) 27 | printf(" L(%s) = %lu mod %i = %lu\n", argv[i], 28 | hash((unsigned char*)argv[i]) & 0xff, 4, 29 | (hash((unsigned char*)argv[i]) & 0xff) % 4); 30 | printf("\n\n"); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /chash/murmur.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 64-bit optimized */ 4 | uint64_t murmur64a(const void *key, unsigned int len, unsigned int seed) 5 | { 6 | const uint64_t m = 0xc6a4a7935bd1e995; 7 | const int r = 47; 8 | 9 | uint64_t h = seed ^ len; 10 | 11 | const uint64_t *data = (const uint64_t *)key; 12 | const uint64_t *end = data + (len/8); 13 | 14 | while(data != end) { 15 | uint64_t k = *data++; 16 | 17 | k *= m; 18 | k ^= k >> r; 19 | k *= m; 20 | 21 | h ^= k; 22 | h *= m; 23 | } 24 | 25 | const unsigned char *data2 = (const unsigned char *)data; 26 | 27 | switch(len & 7) { 28 | case 7: h ^= (uint64_t)(data2[6]) << 48; 29 | case 6: h ^= (uint64_t)(data2[5]) << 40; 30 | case 5: h ^= (uint64_t)(data2[4]) << 32; 31 | case 4: h ^= (uint64_t)(data2[3]) << 24; 32 | case 3: h ^= (uint64_t)(data2[2]) << 16; 33 | case 2: h ^= (uint64_t)(data2[1]) << 8; 34 | case 1: h ^= (uint64_t)(data2[0]); 35 | h *= m; 36 | }; 37 | 38 | h ^= h >> r; 39 | h *= m; 40 | h ^= h >> r; 41 | 42 | return h; 43 | } 44 | 45 | /* 32-bit optimized */ 46 | uint64_t murmur64b(const void *key, unsigned int len, unsigned int seed) 47 | { 48 | const unsigned int m = 0x5bd1e995; 49 | const int r = 24; 50 | 51 | unsigned int h1 = seed ^ len; 52 | unsigned int h2 = 0; 53 | 54 | const unsigned int *data = (const unsigned int *)key; 55 | 56 | while(len >= 8) { 57 | unsigned int k1 = *data++; 58 | k1 *= m; k1 ^= k1 >> r; k1 *= m; 59 | h1 *= m; h1 ^= k1; 60 | len -= 4; 61 | 62 | unsigned int k2 = *data++; 63 | k2 *= m; k2 ^= k2 >> r; k2 *= m; 64 | h2 *= m; h2 ^= k2; 65 | len -= 4; 66 | } 67 | 68 | if(len >= 4) { 69 | unsigned int k1 = *data++; 70 | k1 *= m; k1 ^= k1 >> r; k1 *= m; 71 | h1 *= m; h1 ^= k1; 72 | len -= 4; 73 | } 74 | 75 | switch(len) { 76 | case 3: h2 ^= ((unsigned char *)data)[2] << 16; 77 | case 2: h2 ^= ((unsigned char *)data)[1] << 8; 78 | case 1: h2 ^= ((unsigned char *)data)[0]; 79 | h2 *= m; 80 | }; 81 | 82 | h1 ^= h2 >> 18; h1 *= m; 83 | h2 ^= h1 >> 22; h2 *= m; 84 | h1 ^= h2 >> 17; h1 *= m; 85 | 86 | uint64_t h = h1; 87 | h = (h << 32) | h2; 88 | 89 | return h; 90 | } 91 | -------------------------------------------------------------------------------- /chash/ring.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "dist.h" 7 | 8 | int main(int argc, char **argv) 9 | { 10 | int spread; 11 | int quiet; 12 | 13 | int opt; 14 | while ((opt = getopt(argc, argv, "qs:")) != -1) { 15 | switch (opt) { 16 | case 'q': quiet = 1; break; 17 | case 's': spread = atoi(optarg); break; 18 | default: 19 | fprintf(stderr, "USAGE: %s [-q] [-s spread]\n", argv[0]); 20 | return 1; 21 | } 22 | } 23 | 24 | ring_t ring = { .spread = spread ? spread : 16 }; 25 | node_t nodes[4] = { 26 | { .name = "node01.ring.example.com", .weight = 1 }, 27 | { .name = "node02.ring.example.com", .weight = 2 }, 28 | { .name = "node03.ring.example.com", .weight = 1 }, 29 | { .name = "node04.ring.example.com", .weight = 1 } 30 | }; 31 | 32 | int rc = ring_init(&ring, nodes, 4); 33 | assert(rc == 0); 34 | 35 | int i; 36 | for (i = 0; !quiet && i < ring.len; i++) 37 | printf("%#018lx %i %s\n", ring.vnodes[i].key, 38 | ring.vnodes[i].node->weight, ring.vnodes[i].node->name); 39 | 40 | int count = 0; 41 | char buf[8192]; 42 | while ((fgets(buf, 8192, stdin))) { 43 | char *nl = strchr(buf, '\n'); 44 | if (nl) *nl = '\0'; 45 | 46 | node_t *n = lookup(&ring, buf); 47 | if (n) { 48 | count++; 49 | n->u++; 50 | if (!quiet) 51 | printf("key %-30s (%#018lx) is at %s (%i)\n", 52 | buf, murmur64a(buf, strlen(buf), 0), 53 | n ? n->name : "(nil)", 54 | n ? n->weight : 0); 55 | } else { 56 | printf("key %s not found in ring!\n", buf); 57 | } 58 | } 59 | 60 | if (!quiet) printf("\n\n"); 61 | for (i = 0; i < 4; i++) { 62 | printf("node %s (%i) accounts for % 5i/%i keys (%5.2lf%%)\n", 63 | nodes[i].name, nodes[i].weight, nodes[i].u, count, nodes[i].u * 100.0 / count); 64 | } 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /errno/.gitignore: -------------------------------------------------------------------------------- 1 | errno 2 | elist.h 3 | -------------------------------------------------------------------------------- /errno/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := -Wall -g2 -O0 -Wno-unused 2 | 3 | BINARIES := 4 | BINARIES += errno 5 | 6 | all: $(BINARIES) 7 | clean: 8 | rm -f *.o $(BINARIES) 9 | errno.o: errno.c elist.h 10 | elist.h: elist 11 | ./mklist elist > $@ 12 | -------------------------------------------------------------------------------- /errno/elist: -------------------------------------------------------------------------------- 1 | E2BIG 2 | EACCES 3 | EADDRINUSE 4 | EADDRNOTAVAIL 5 | EAFNOSUPPORT 6 | EAGAIN 7 | EALREADY 8 | EBADE 9 | EBADF 10 | EBADFD 11 | EBADMSG 12 | EBADR 13 | EBADRQC 14 | EBADSLT 15 | EBUSY 16 | ECANCELED 17 | ECHILD 18 | ECHRNG 19 | ECOMM 20 | ECONNABORTED 21 | ECONNREFUSED 22 | ECONNRESET 23 | EDEADLK 24 | EDEADLOCK 25 | EDESTADDRREQ 26 | EDOM 27 | EDQUOT 28 | EEXIST 29 | EFAULT 30 | EFBIG 31 | EHOSTDOWN 32 | EHOSTUNREACH 33 | EIDRM 34 | EILSEQ 35 | EINPROGRESS 36 | EINTR 37 | EINVAL 38 | EIO 39 | EISCONN 40 | EISDIR 41 | EISNAM 42 | EKEYEXPIRED 43 | EKEYREJECTED 44 | EKEYREVOKED 45 | EL2HLT 46 | EL2NSYNC 47 | EL3HLT 48 | EL3RST 49 | ELIBACC 50 | ELIBBAD 51 | ELIBMAX 52 | ELIBSCN 53 | ELIBEXEC 54 | ELOOP 55 | EMEDIUMTYPE 56 | EMFILE 57 | EMLINK 58 | EMSGSIZE 59 | EMULTIHOP 60 | ENAMETOOLONG 61 | ENETDOWN 62 | ENETRESET 63 | ENETUNREACH 64 | ENFILE 65 | ENOBUFS 66 | ENODATA 67 | ENODEV 68 | ENOENT 69 | ENOEXEC 70 | ENOKEY 71 | ENOLCK 72 | ENOLINK 73 | ENOMEDIUM 74 | ENOMEM 75 | ENOMSG 76 | ENONET 77 | ENOPKG 78 | ENOPROTOOPT 79 | ENOSPC 80 | ENOSR 81 | ENOSTR 82 | ENOSYS 83 | ENOTBLK 84 | ENOTCONN 85 | ENOTDIR 86 | ENOTEMPTY 87 | ENOTSOCK 88 | ENOTSUP 89 | ENOTTY 90 | ENOTUNIQ 91 | ENXIO 92 | EOPNOTSUPP 93 | EOVERFLOW 94 | EPERM 95 | EPFNOSUPPORT 96 | EPIPE 97 | EPROTO 98 | EPROTONOSUPPORT 99 | EPROTOTYPE 100 | ERANGE 101 | EREMCHG 102 | EREMOTE 103 | EREMOTEIO 104 | ERESTART 105 | EROFS 106 | ESHUTDOWN 107 | ESPIPE 108 | ESOCKTNOSUPPORT 109 | ESRCH 110 | ESTALE 111 | ESTRPIPE 112 | ETIME 113 | ETIMEDOUT 114 | ETXTBSY 115 | EUCLEAN 116 | EUNATCH 117 | EUSERS 118 | EWOULDBLOCK 119 | EXDEV 120 | EXFULL 121 | -------------------------------------------------------------------------------- /errno/errno.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "elist.h" 7 | 8 | int main (int argc, char **argv) 9 | { 10 | elist_init(); 11 | int i; 12 | for (i = 1; argv[i]; i++) { 13 | char *x = NULL; 14 | int err = strtoul(argv[i], &x, 10); 15 | if (x && *x) { 16 | fprintf(stderr, "'%s': unrecognized errno value\n", argv[i]); 17 | continue; 18 | } 19 | if (err < 0 || err > 255) { 20 | fprintf(stderr, "%i: out-of-range for an errno value\n", err); 21 | continue; 22 | } 23 | 24 | fprintf(stderr, "% 4i %-16s %s\n", 25 | err, CONST[err] ? CONST[err] : "-", strerror(err)); 26 | } 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /errno/mklist: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # elist can be generated with: 3 | # `man errno | grep '^ * E' | awk '{print $1}' > elist` 4 | 5 | print <= 0 && (x) <= 255) CONST[(x)] = #x; } while (0) 10 | 11 | static void elist_init(void) 12 | { 13 | EOF 14 | 15 | for (<>) { 16 | chomp; 17 | print <", "io.fifo" or die "io.fifo: $!\n"; 5 | print $fh $_[0]; 6 | close $fh; 7 | } 8 | submit "[$ts] SCHEDULE_SERVICE_CHECK;host.example.com;foo$_;$ts\n" for 1 .. 963; 9 | submit "[$ts] SCHEDULE_SERVICE_CHECK;host;service;$ts\n"; 10 | -------------------------------------------------------------------------------- /fifos/io.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MAX_LEN 2048 10 | 11 | static int total; 12 | static int i = 0; 13 | 14 | void exec_command(const char *cmd) 15 | { 16 | i++; total += strlen(cmd); 17 | 18 | fprintf(stderr, "."); 19 | if (cmd[strlen(cmd) - 1] != '\n' || cmd[0] != '[') 20 | fprintf(stderr, "<< (%i) read %i bytes (%i total): '%s'>>", i, (int)strlen(cmd), total, cmd); 21 | } 22 | 23 | void process_command_file(FILE *io) 24 | { 25 | char buf[MAX_LEN]; 26 | int fd = fileno(io); 27 | 28 | struct pollfd pfd; 29 | 30 | for (;;) { 31 | pfd.fd = fd; 32 | pfd.events = POLLIN; 33 | 34 | int pollval = poll(&pfd, 1, 500); 35 | assert(pollval != -1); 36 | 37 | if (pollval == 0) 38 | continue; 39 | 40 | //clearerr(io); 41 | while (fgets(buf, MAX_LEN, io) != NULL) 42 | exec_command(buf); 43 | fprintf(stderr, "\nEOF!\n"); 44 | } 45 | } 46 | 47 | int main(int argc, char **argv) 48 | { 49 | unlink("io.fifo"); 50 | system("mkfifo io.fifo"); 51 | 52 | int fd = open("io.fifo", O_RDWR | O_NONBLOCK); 53 | assert(fd >= 0); 54 | 55 | FILE *fp = fdopen(fd, "r"); 56 | assert(fp != NULL); 57 | 58 | process_command_file(fp); 59 | 60 | close(fd); 61 | fclose(fp); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /fifos/io2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define MAX_LEN 2048 11 | 12 | static int total; 13 | static int i = 0; 14 | 15 | void exec_command(const char *cmd) 16 | { 17 | i++; total += strlen(cmd); 18 | 19 | fprintf(stderr, "."); 20 | if (cmd[strlen(cmd) - 1] != '\n' || cmd[0] != '[') 21 | fprintf(stderr, "<< (%i) read %i bytes (%i total): '%s'>>", i, (int)strlen(cmd), total, cmd); 22 | } 23 | 24 | void process_command_file(int fd) 25 | { 26 | char command[MAX_LEN]; 27 | static char buf[MAX_LEN]; 28 | static size_t offset = 0; 29 | 30 | struct pollfd pfd; 31 | 32 | for (;;) { 33 | pfd.fd = fd; 34 | pfd.events = POLLIN; 35 | 36 | int pollval = poll(&pfd, 1, 500); 37 | assert(pollval != -1); 38 | 39 | if (pollval == 0) 40 | continue; 41 | 42 | ssize_t n = read(fd, buf + offset, MAX_LEN - offset - 1); 43 | if (n == 0) { 44 | fprintf(stderr, "EOF!\n"); 45 | break; 46 | } 47 | if (n == -1) { 48 | if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) 49 | continue; 50 | perror("read"); 51 | break; 52 | } 53 | buf[offset + n] = '\0'; 54 | 55 | char *a; 56 | for (;;) { 57 | a = buf; 58 | while (*a && *a != '\n') a++; 59 | if (!*a) break; 60 | a++; 61 | 62 | memset(command, 0, MAX_LEN); 63 | memcpy(command, buf, a - buf); 64 | memmove(buf, a, MAX_LEN - (a - buf)); 65 | 66 | exec_command(command); 67 | } 68 | offset = a - buf; 69 | } 70 | fprintf(stderr, "\nEOF!\n"); 71 | } 72 | 73 | int main(int argc, char **argv) 74 | { 75 | unlink("io.fifo"); 76 | system("mkfifo io.fifo"); 77 | 78 | int fd = open("io.fifo", O_RDWR | O_NONBLOCK); 79 | assert(fd >= 0); 80 | 81 | process_command_file(fd); 82 | fprintf(stderr, "\n\nprocessed %i items / %i bytes\n", i, total); 83 | 84 | close(fd); 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /fifos/size.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv) 7 | { 8 | int pfd[2]; 9 | if (pipe(pfd) != 0) { 10 | perror("pipe()"); 11 | return 1; 12 | } 13 | 14 | printf("pipe buffer is %i bytes\n", fcntl(pfd[0], F_GETPIPE_SZ)); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /flags/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | flags 3 | -------------------------------------------------------------------------------- /flags/flags.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define FLAG_A 1 5 | #define FLAG_B 2 6 | #define FLAG_C 4 7 | 8 | int main(int argc, char **argv) 9 | { 10 | int i; 11 | 12 | srand(99); /* need arbitrary numbers */ 13 | for (i = 0; i < 40; i++) { 14 | int v = (int)(rand() * 1.0 / RAND_MAX * 8); 15 | 16 | fprintf(stderr, "% 2d: ", v); 17 | /* this doesn't work: 18 | switch (1) { 19 | case v & FLAG_A: fprintf(stderr, "A "); break; 20 | case v & FLAG_B: fprintf(stderr, "B "); break; 21 | case v & FLAG_C: fprintf(stderr, "C "); break; 22 | } 23 | */ 24 | /* but this does: */ 25 | if (v & FLAG_A) fprintf(stderr, "A "); 26 | if (v & FLAG_B) fprintf(stderr, "B "); 27 | if (v & FLAG_C) fprintf(stderr, "C "); 28 | fprintf(stderr, "\n"); 29 | } 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /fork/fork.c: -------------------------------------------------------------------------------- 1 | /* public domain */ 2 | #include 3 | #include 4 | #include 5 | 6 | int main (int argc, char **argv) 7 | { 8 | if (argc == 1) { 9 | fprintf(stderr, "USAGE: %s command --to --run -forked\n", argv[0]); 10 | return 1; 11 | } 12 | 13 | pid_t pid = fork(); 14 | if (pid < 0) { 15 | perror("fork() failed"); 16 | return 1; 17 | } 18 | 19 | if (pid > 0) return 0; 20 | if (!freopen("/dev/null", "r", stdin)) perror("/dev/null"); 22 | if (!freopen("/dev/null", "w", stderr)) perror("2>/dev/null"); 23 | 24 | execvp(argv[1], argv + 1); 25 | perror("exec() failed"); 26 | return 1; 27 | } 28 | -------------------------------------------------------------------------------- /fuse/nullfs/.gitignore: -------------------------------------------------------------------------------- 1 | nullfs 2 | *.o 3 | -------------------------------------------------------------------------------- /fuse/nullfs/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := $(shell pkg-config fuse --cflags) 2 | LDLIBS := $(shell pkg-config fuse --libs) 3 | 4 | nullfs: nullfs.o 5 | 6 | clean: 7 | rm -f nullfs *.o 8 | -------------------------------------------------------------------------------- /fuse/nullfs/nullfs.c: -------------------------------------------------------------------------------- 1 | #define FUSE_USE_VERSION 26 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | int nullfs_getattr(const char *path, struct stat *st) 22 | { 23 | return 0; 24 | } 25 | 26 | int nullfs_readlink(const char *path, char *target, size_t len) 27 | { 28 | return 1; 29 | } 30 | 31 | int nullfs_mknod(const char *path, mode_t mode, dev_t dev) 32 | { 33 | return 0; 34 | } 35 | 36 | int nullfs_mkdir(const char *path, mode_t mode) 37 | { 38 | return 0; 39 | } 40 | 41 | int nullfs_unlink(const char *path) 42 | { 43 | return 0; 44 | } 45 | 46 | int nullfs_rmdir(const char *path) 47 | { 48 | return 0; 49 | } 50 | 51 | int nullfs_symlink(const char *path, const char *target) 52 | { 53 | return 0; 54 | } 55 | 56 | int nullfs_rename(const char *oldpath, const char *newpath) 57 | { 58 | return 0; 59 | } 60 | 61 | int nullfs_link(const char *oldpath, const char *newpath) 62 | { 63 | return 0; 64 | } 65 | 66 | int nullfs_chmod(const char *path, mode_t mode) 67 | { 68 | return 0; 69 | } 70 | 71 | int nullfs_chown(const char *path, uid_t uid, gid_t gid) 72 | { 73 | return 0; 74 | } 75 | 76 | int nullfs_truncate(const char *path, off_t newsize) 77 | { 78 | return 0; 79 | } 80 | 81 | int nullfs_utimens(const char *path, const struct timespec tv[2]) 82 | { 83 | return 0; 84 | } 85 | 86 | int nullfs_open(const char *path, struct fuse_file_info *info) 87 | { 88 | return 0; 89 | } 90 | 91 | int nullfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *info) 92 | { 93 | return 0; 94 | } 95 | 96 | int nullfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *info) 97 | { 98 | return 0; 99 | } 100 | 101 | int nullfs_statfs(const char *path, struct statvfs *st) 102 | { 103 | return -EINVAL; 104 | } 105 | 106 | int nullfs_flush(const char *path, struct fuse_file_info *info) 107 | { 108 | return 0; 109 | } 110 | 111 | int nullfs_release(const char *path, struct fuse_file_info *info) 112 | { 113 | return 0; 114 | } 115 | 116 | int nullfs_fsync(const char *path, int datasync, struct fuse_file_info *info) 117 | { 118 | return 0; 119 | } 120 | 121 | int nullfs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) 122 | { 123 | return 0; 124 | } 125 | 126 | int nullfs_getxattr(const char *path, const char *name, char *value, size_t size) 127 | { 128 | return 1; 129 | } 130 | 131 | int nullfs_listxattr(const char *path, char *list, size_t size) 132 | { 133 | return 1; 134 | } 135 | 136 | int nullfs_removexattr(const char *path, const char *name) 137 | { 138 | return 0; 139 | } 140 | 141 | int nullfs_opendir(const char *path, struct fuse_file_info *info) 142 | { 143 | return 0; 144 | } 145 | 146 | int nullfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *info) 147 | { 148 | return 0; 149 | } 150 | 151 | int nullfs_releasedir(const char *path, struct fuse_file_info *info) 152 | { 153 | return 0; 154 | } 155 | 156 | int nullfs_fsyncdir(const char *path, int datasync, struct fuse_file_info *info) 157 | { 158 | return 0; 159 | } 160 | 161 | void *nullfs_init(struct fuse_conn_info *conn) 162 | { 163 | return NULL; 164 | } 165 | 166 | void nullfs_destroy(void *userdata) 167 | { 168 | } 169 | 170 | int nullfs_access(const char *path, int mask) 171 | { 172 | return 0; 173 | } 174 | 175 | int nullfs_create(const char *path, mode_t mode, struct fuse_file_info *info) 176 | { 177 | return 0; 178 | } 179 | 180 | int nullfs_ftruncate(const char *path, off_t offset, struct fuse_file_info *info) 181 | { 182 | return 0; 183 | } 184 | 185 | int nullfs_fgetattr(const char *path, struct stat *statbuf, struct fuse_file_info *info) 186 | { 187 | return 0; 188 | } 189 | 190 | struct fuse_operations nullfs_oper = { 191 | .getattr = nullfs_getattr, 192 | .readlink = nullfs_readlink, 193 | .getdir = NULL, /* deprecated */ 194 | .mknod = nullfs_mknod, 195 | .mkdir = nullfs_mkdir, 196 | .unlink = nullfs_unlink, 197 | .rmdir = nullfs_rmdir, 198 | .symlink = nullfs_symlink, 199 | .rename = nullfs_rename, 200 | .link = nullfs_link, 201 | .chmod = nullfs_chmod, 202 | .chown = nullfs_chown, 203 | .truncate = nullfs_truncate, 204 | 205 | .utime = NULL, 206 | .utimens = nullfs_utimens, 207 | .open = nullfs_open, 208 | .read = nullfs_read, 209 | .write = nullfs_write, 210 | .statfs = nullfs_statfs, 211 | .flush = nullfs_flush, 212 | .release = nullfs_release, 213 | .fsync = nullfs_fsync, 214 | .setxattr = nullfs_setxattr, 215 | .getxattr = nullfs_getxattr, 216 | .listxattr = nullfs_listxattr, 217 | .removexattr = nullfs_removexattr, 218 | .opendir = nullfs_opendir, 219 | .readdir = nullfs_readdir, 220 | .releasedir = nullfs_releasedir, 221 | .fsyncdir = nullfs_fsyncdir, 222 | .init = nullfs_init, 223 | .destroy = nullfs_destroy, 224 | .access = nullfs_access, 225 | .create = nullfs_create, 226 | .ftruncate = nullfs_ftruncate, 227 | .fgetattr = nullfs_fgetattr, 228 | }; 229 | 230 | int main(int argc, char **argv) 231 | { 232 | int rc = fuse_main(argc, argv, &nullfs_oper, NULL); 233 | return rc; 234 | } 235 | -------------------------------------------------------------------------------- /insist/.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | traditional 3 | modern 4 | -------------------------------------------------------------------------------- /insist/Makefile: -------------------------------------------------------------------------------- 1 | all: main 2 | clean: 3 | rm -f main traditional modern *.o 4 | 5 | main: main.o 6 | 7 | .PHONY: all clean 8 | -------------------------------------------------------------------------------- /insist/insist.h: -------------------------------------------------------------------------------- 1 | #ifndef INSIST_DOT_H 2 | #define INSIST_DOT_H 3 | 4 | /* 5 | Copyright (c) 2016, James Hunt 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | /* ASSERTION_OUTPUT_STREAM defines the FILE* that the `insist()` macro will 31 | print error messages to, before exiting. If ASSERTION_PRINT_ALWAYS is also 32 | defined, this stream will be used to print successes as well. */ 33 | #ifndef ASSERTION_OUTPUT_STREAM 34 | #define ASSERTION_OUTPUT_STREAM stderr 35 | #endif 36 | 37 | /* ASSERTION_FAIL_EXIT_CODE defines the exit code value that the `insist()` 38 | macro will exit with, in the event of an assertion failure. */ 39 | #ifndef ASSERTION_FAIL_EXIT_CODE 40 | #define ASSERTION_FAIL_EXIT_CODE 7 41 | #endif 42 | 43 | /* Two (2) #define's control the behavior of the `insist()` macro: 44 | 45 | ASSERTION_DEBUGGING causes the function (__func__), file (__FILE__) and 46 | line number (__LINE__) of the assertion call to be printed with the 47 | failure message, which can be useful for tracking down flaky assertions. 48 | 49 | ASSERTION_PRINT_ALWAYS causes `insist()` to *always* print a diagnostic 50 | (to ASSERTION_OUTPUT_STREAM), regardless of success / failure. The 51 | program will not abort on success, of course, but the messages may prove 52 | useful for output verification during testing. 53 | 54 | Note that ASSERTION_PRINT_ALWAYS is only checked if ASSERTION_DEBUGGING 55 | is defined. That is, you cannot get the "print always" behavior without 56 | the "debugging" behavior. 57 | */ 58 | #if !defined(ASSERTION_DEBUGGING) 59 | # define insist(test,msg) ({ \ 60 | if (!(test)) { \ 61 | fprintf((ASSERTION_OUTPUT_STREAM), "ASSERTION FAILED: " msg " (`" #test "` was false)\n"); \ 62 | exit((ASSERTION_FAIL_EXIT_CODE)); \ 63 | } \ 64 | }) 65 | #elif !defined(ASSERTION_PRINT_ALWAYS) 66 | # define insist(test,msg) ({ \ 67 | if (!(test)) { \ 68 | void *buffer[128]; int size; \ 69 | fprintf((ASSERTION_OUTPUT_STREAM), "ASSERTION FAILED: " msg " (`" #test "` was false, in %s(), at %s:%i)\n", __func__, __FILE__, __LINE__); \ 70 | size = backtrace(buffer, size); \ 71 | fprintf((ASSERTION_OUTPUT_STREAM), "%i frames\n", size); \ 72 | backtrace_symbols_fd(buffer, size, fileno(ASSERTION_OUTPUT_STREAM)); \ 73 | fprintf((ASSERTION_OUTPUT_STREAM), "done\n"); \ 74 | exit((ASSERTION_FAIL_EXIT_CODE)); \ 75 | } \ 76 | }) 77 | #else 78 | # define insist(test,msg) ({ \ 79 | if (!(test)) { \ 80 | void *buffer[128]; int size; \ 81 | fprintf((ASSERTION_OUTPUT_STREAM), "ASSERTION FAILED: " msg " (`" #test "` was false, in %s(), at %s:%i)\n", __func__, __FILE__, __LINE__); \ 82 | size = backtrace(buffer, size); \ 83 | backtrace_symbols_fd(buffer, size, fileno(ASSERTION_OUTPUT_STREAM)); \ 84 | fprintf((ASSERTION_OUTPUT_STREAM), "done\n"); \ 85 | exit((ASSERTION_FAIL_EXIT_CODE)); \ 86 | } else { \ 87 | fprintf((ASSERTION_OUTPUT_STREAM), "assertion succeeded: " msg " (`" #test "` was true, in %s(), at %s:%i)\n", __func__, __FILE__, __LINE__); \ 88 | } \ 89 | }) 90 | #endif 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /insist/main.c: -------------------------------------------------------------------------------- 1 | #define ASSERTION_OUTPUT_STREAM stdout 2 | #define ASSERTION_FAIL_EXIT_CODE 23 3 | #define ASSERTION_DEBUGGING 4 | #define ASSERTION_PRINT_ALWAYS 5 | #include "insist.h" 6 | #include 7 | 8 | int main(int argc, char **argv) { 9 | int x = 421; 10 | insist(x == 42, "x should be the answer to life, the universe, and everything"); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /insist/modern.c: -------------------------------------------------------------------------------- 1 | #define ASSERTION_DEBUGGING 2 | #include "insist.h" 3 | #include 4 | 5 | int _strlen(const char *s) 6 | { 7 | insist(s != NULL, "_strlen(NULL) is undefined"); 8 | 9 | int n = 0; 10 | while (*s++) 11 | n++; 12 | 13 | return n; 14 | } 15 | 16 | void thunk() { 17 | _strlen(NULL); /* should fail */ 18 | } 19 | 20 | int main(int argc, char **argv) 21 | { 22 | thunk(); 23 | thunk(); 24 | thunk(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /insist/modern.s: -------------------------------------------------------------------------------- 1 | .section __TEXT,__text,regular,pure_instructions 2 | .macosx_version_min 10, 11 3 | .globl __strlen 4 | .align 4, 0x90 5 | __strlen: ## @_strlen 6 | .cfi_startproc 7 | ## BB#0: 8 | pushq %rbp 9 | Ltmp0: 10 | .cfi_def_cfa_offset 16 11 | Ltmp1: 12 | .cfi_offset %rbp, -16 13 | movq %rsp, %rbp 14 | Ltmp2: 15 | .cfi_def_cfa_register %rbp 16 | subq $1088, %rsp ## imm = 0x440 17 | movq ___stack_chk_guard@GOTPCREL(%rip), %rax 18 | movq (%rax), %rax 19 | movq %rax, -8(%rbp) 20 | movq %rdi, -1048(%rbp) 21 | cmpq $0, -1048(%rbp) 22 | jne LBB0_2 23 | ## BB#1: 24 | leaq L_.str(%rip), %rsi 25 | leaq L___func__._strlen(%rip), %rdx 26 | leaq L_.str.1(%rip), %rcx 27 | movl $7, %r8d 28 | movq ___stderrp@GOTPCREL(%rip), %rax 29 | movq (%rax), %rdi 30 | movb $0, %al 31 | callq _fprintf 32 | leaq -1040(%rbp), %rdi 33 | movl -1052(%rbp), %esi 34 | movl %eax, -1060(%rbp) ## 4-byte Spill 35 | callq _backtrace 36 | leaq L_.str.2(%rip), %rsi 37 | movq ___stderrp@GOTPCREL(%rip), %rcx 38 | movl %eax, -1052(%rbp) 39 | movq (%rcx), %rdi 40 | movl -1052(%rbp), %edx 41 | movb $0, %al 42 | callq _fprintf 43 | movq ___stderrp@GOTPCREL(%rip), %rcx 44 | leaq -1040(%rbp), %rdi 45 | movl -1052(%rbp), %esi 46 | movq (%rcx), %rcx 47 | movq %rdi, -1072(%rbp) ## 8-byte Spill 48 | movq %rcx, %rdi 49 | movl %eax, -1076(%rbp) ## 4-byte Spill 50 | movl %esi, -1080(%rbp) ## 4-byte Spill 51 | callq _fileno 52 | movq -1072(%rbp), %rdi ## 8-byte Reload 53 | movl -1080(%rbp), %esi ## 4-byte Reload 54 | movl %eax, %edx 55 | callq _backtrace_symbols_fd 56 | leaq L_.str.3(%rip), %rsi 57 | movq ___stderrp@GOTPCREL(%rip), %rcx 58 | movq (%rcx), %rdi 59 | movb $0, %al 60 | callq _fprintf 61 | movl $7, %edi 62 | movl %eax, -1084(%rbp) ## 4-byte Spill 63 | callq _exit 64 | LBB0_2: 65 | movl $0, -1056(%rbp) 66 | LBB0_3: ## =>This Inner Loop Header: Depth=1 67 | movq -1048(%rbp), %rax 68 | movq %rax, %rcx 69 | addq $1, %rcx 70 | movq %rcx, -1048(%rbp) 71 | cmpb $0, (%rax) 72 | je LBB0_5 73 | ## BB#4: ## in Loop: Header=BB0_3 Depth=1 74 | movl -1056(%rbp), %eax 75 | addl $1, %eax 76 | movl %eax, -1056(%rbp) 77 | jmp LBB0_3 78 | LBB0_5: 79 | movq ___stack_chk_guard@GOTPCREL(%rip), %rax 80 | movl -1056(%rbp), %ecx 81 | movq (%rax), %rax 82 | cmpq -8(%rbp), %rax 83 | movl %ecx, -1088(%rbp) ## 4-byte Spill 84 | jne LBB0_7 85 | ## BB#6: 86 | movl -1088(%rbp), %eax ## 4-byte Reload 87 | addq $1088, %rsp ## imm = 0x440 88 | popq %rbp 89 | retq 90 | LBB0_7: 91 | callq ___stack_chk_fail 92 | .cfi_endproc 93 | 94 | .globl _thunk 95 | .align 4, 0x90 96 | _thunk: ## @thunk 97 | .cfi_startproc 98 | ## BB#0: 99 | pushq %rbp 100 | Ltmp3: 101 | .cfi_def_cfa_offset 16 102 | Ltmp4: 103 | .cfi_offset %rbp, -16 104 | movq %rsp, %rbp 105 | Ltmp5: 106 | .cfi_def_cfa_register %rbp 107 | subq $16, %rsp 108 | xorl %eax, %eax 109 | movl %eax, %edi 110 | callq __strlen 111 | movl %eax, -4(%rbp) ## 4-byte Spill 112 | addq $16, %rsp 113 | popq %rbp 114 | retq 115 | .cfi_endproc 116 | 117 | .globl _main 118 | .align 4, 0x90 119 | _main: ## @main 120 | .cfi_startproc 121 | ## BB#0: 122 | pushq %rbp 123 | Ltmp6: 124 | .cfi_def_cfa_offset 16 125 | Ltmp7: 126 | .cfi_offset %rbp, -16 127 | movq %rsp, %rbp 128 | Ltmp8: 129 | .cfi_def_cfa_register %rbp 130 | subq $16, %rsp 131 | movl $0, -4(%rbp) 132 | movl %edi, -8(%rbp) 133 | movq %rsi, -16(%rbp) 134 | callq _thunk 135 | callq _thunk 136 | callq _thunk 137 | xorl %eax, %eax 138 | addq $16, %rsp 139 | popq %rbp 140 | retq 141 | .cfi_endproc 142 | 143 | .section __TEXT,__cstring,cstring_literals 144 | L_.str: ## @.str 145 | .asciz "ASSERTION FAILED: _strlen(NULL) is undefined (`s != NULL` was false, in %s(), at %s:%i)\n" 146 | 147 | L___func__._strlen: ## @__func__._strlen 148 | .asciz "_strlen" 149 | 150 | L_.str.1: ## @.str.1 151 | .asciz "modern.c" 152 | 153 | L_.str.2: ## @.str.2 154 | .asciz "%i frames\n" 155 | 156 | L_.str.3: ## @.str.3 157 | .asciz "done\n" 158 | 159 | 160 | .subsections_via_symbols 161 | -------------------------------------------------------------------------------- /insist/traditional.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int _strlen(const char *s) 5 | { 6 | assert(s != NULL); 7 | 8 | int n = 0; 9 | while (*s++) 10 | n++; 11 | 12 | return n; 13 | } 14 | 15 | int main(int argc, char **argv) 16 | { 17 | _strlen(NULL); /* should fail */ 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /knave/.gitignore: -------------------------------------------------------------------------------- 1 | knave 2 | wastrel 3 | -------------------------------------------------------------------------------- /knave/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := -Wall -g2 -O0 -Wno-unused 2 | 3 | BINARIES := 4 | BINARIES += knave 5 | 6 | all: $(BINARIES) 7 | ln -sf knave wastrel 8 | clean: 9 | rm -f *.o $(BINARIES) 10 | -------------------------------------------------------------------------------- /knave/knave.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) 6 | { 7 | char *bin = strrchr(argv[0], '/'); 8 | if (!bin) bin = argv[0]; 9 | else bin++; 10 | 11 | if (strcmp(bin, "wastrel") == 0) { 12 | fprintf(stderr, "wastrel\n"); 13 | int n = (argc < 2 ? 1024 : atoi(argv[1])) * 1024; 14 | char **m = calloc(n / 64, sizeof(char **)); 15 | 16 | fprintf(stderr, "allocating %u 64k blocks (%uM)\n", n / 64, n / 1024); 17 | int i; 18 | for (i = 0; i < n / 64; i++) { 19 | m[i] = calloc(64 * 1024, sizeof(char)); 20 | memset(m, rand(), 64 * 1024); 21 | } 22 | 23 | // FIXME: can we just use a single sbrk() call to extend the heap? 24 | 25 | } else { 26 | fprintf(stderr, "unknown tool '%s'\n", bin); 27 | return 1; 28 | } 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /lexer-ll/NOTES: -------------------------------------------------------------------------------- 1 | The L parser works kind of like lex, but doesn't support a lot of things, and it aims to be simple to parse and reason about. 2 | 3 | The language is basically: 4 | 5 | 6 | spec: [preamble] '^----$' rules '^----$' [postamble] 7 | rules: 8 | | rules rule; 9 | rule: regex 10 | 11 | preamble and postamble are copied verbatim, with no introspection. 12 | 13 | -------------------------------------------------------------------------------- /lexer-ll/bql.ll: -------------------------------------------------------------------------------- 1 | /* c pre-amble */ 2 | #define TOKEN_VAR 1 3 | #define TOKEN_QSTRING 2 4 | ---- 5 | a|b|c|x|y|z 6 | recognize(TOKEN_VAR, NULL, NULL); 7 | 8 | ".*" 9 | recognize(TOKEN_QSTRING, 10 | lexeme(1, ll.lexeme.len - 1), 11 | ll.lexeme.len - 2); 12 | ---- 13 | /* c post-amble */ 14 | #include 15 | void done() { 16 | printf("all done!\n"); 17 | } 18 | -------------------------------------------------------------------------------- /lexer-ll/bql.ll.c: -------------------------------------------------------------------------------- 1 | /* c pre-amble */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void * lex_open(const char *); 11 | void lex_close(void *); 12 | int lex_token(void *); 13 | 14 | typedef struct { 15 | const char *file; 16 | 17 | char *source; 18 | size_t len; 19 | 20 | size_t line; 21 | size_t column; 22 | 23 | size_t dot; 24 | } lexer; 25 | 26 | #define LEXER(v) ((lexer *)(v)) 27 | 28 | void * 29 | lex_open(const char *file) 30 | { 31 | int fd = -1; 32 | void *lx = NULL; 33 | 34 | off_t size; 35 | ssize_t nread; 36 | 37 | assert(file != NULL); 38 | 39 | lx = malloc(sizeof(lexer)); 40 | if (!lx) goto failed; 41 | 42 | fd = open(file, O_RDONLY); 43 | if (fd < 0) goto failed; 44 | 45 | size = lseek(fd, 0, SEEK_END); 46 | if (size < 0) goto failed; 47 | 48 | if (lseek(fd, 0, SEEK_SET) < 0) 49 | goto failed; 50 | 51 | LEXER(lx)->len = size; 52 | LEXER(lx)->source = malloc(LEXER(lx)->len); 53 | if (!LEXER(lx)->source) goto failed; 54 | 55 | nread = read(fd, LEXER(lx)->source, LEXER(lx)->len); 56 | if (nread < 0) goto failed; 57 | if ((size_t)nread != LEXER(lx)->len) { 58 | errno = EIO; 59 | goto failed; 60 | } 61 | 62 | LEXER(lx)->line = LEXER(lx)->column = 1; 63 | LEXER(lx)->dot = 0; 64 | 65 | close(fd); 66 | return LEXER(lx); 67 | 68 | failed: 69 | if (fd >= 0) close(fd); 70 | lex_close(lx); 71 | return NULL; 72 | } 73 | 74 | void 75 | lex_close(void *lx) { 76 | if (!lx) return; 77 | free(LEXER(lx)->source); 78 | free(LEXER(lx)); 79 | } 80 | 81 | const char * 82 | lex_lexeme(void *lx) 83 | { 84 | } 85 | 86 | int 87 | lex_token(void *lx) 88 | { 89 | } 90 | 91 | int 92 | lex(void *lx) 93 | { 94 | if (LEXER(lx)->dot == LEXER(lx)->len) 95 | return 0; 96 | #define recognize(t,l,u) 97 | #undef recognize 98 | 99 | LEXER(lx)->dot++; 100 | return 1; 101 | } 102 | 103 | /* c post-amble */ 104 | -------------------------------------------------------------------------------- /lexer-ll/bql.ll.h: -------------------------------------------------------------------------------- 1 | #ifndef REALLY_LONG_IDENTIFIER_FIXME 2 | #define REALLY_LONG_IDENTIFIER_FIXME 3 | 4 | void * lex_open(const char *); 5 | void lex_close(void *); 6 | int lex(void *); 7 | 8 | const char * lex_lexeme(void *); 9 | int lex_token(void *); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /lexer-ll/bql.regex: -------------------------------------------------------------------------------- 1 | select|from|where|=|(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9)* 2 | -------------------------------------------------------------------------------- /lexer-ll/ll.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | 5 | my (@pre, @post, @rules); 6 | my $rule = undef; 7 | my $section = 1; 8 | while (<>) { 9 | chomp; 10 | if (m/^----+$/) { 11 | $section++; 12 | die "syntax error (too many sections)\n" if $section > 3; 13 | next; 14 | } 15 | if ($section == 1) { 16 | push @pre, "$_\n"; 17 | 18 | } elsif ($section == 3) { 19 | push @rules, $rule if $rule; 20 | $rule = undef; 21 | push @post, "$_\n"; 22 | 23 | } else { 24 | if (m/^\S/) { 25 | push @rules, $rule if $rule; 26 | $rule = { regex => $_, body => [] }; 27 | 28 | } else { 29 | push @{$rule->{body}}, "$_\n"; 30 | } 31 | } 32 | } 33 | die "syntax error (no preamble)" if $section == 1; 34 | die "syntax error (no postamble)" if $section == 2; 35 | 36 | my $spec = { 37 | pre => join('', @pre), 38 | post => join('', @post), 39 | rules => [ map { 40 | $_->{body} = join('', @{$_->{body}}); 41 | $_; 42 | } @rules ] 43 | }; 44 | 45 | use Data::Dumper; 46 | print Dumper($spec); 47 | 48 | my (@starts, @states); 49 | 50 | for my $rule (@rules) { 51 | my $state = @states; 52 | 53 | $states[$state] = {}; 54 | } 55 | 56 | print Dumper(\@starts, \@states); 57 | 58 | -------------------------------------------------------------------------------- /lexer-ll/ll1.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | 5 | my (@pre, @post, @rules); 6 | my $rule = undef; 7 | my $section = 1; 8 | while (<>) { 9 | chomp; 10 | if (m/^----+$/) { 11 | $section++; 12 | die "syntax error (too many sections)\n" if $section > 3; 13 | next; 14 | } 15 | if ($section == 1) { 16 | push @pre, "$_\n"; 17 | 18 | } elsif ($section == 3) { 19 | push @rules, $rule if $rule; 20 | $rule = undef; 21 | push @post, "$_\n"; 22 | 23 | } else { 24 | if (m/^\S/) { 25 | push @rules, $rule if $rule; 26 | $rule = { regex => $_, body => [] }; 27 | 28 | } else { 29 | push @{$rule->{body}}, "$_\n"; 30 | } 31 | } 32 | } 33 | die "syntax error (no preamble)" if $section == 1; 34 | die "syntax error (no postamble)" if $section == 2; 35 | 36 | my $spec = { 37 | pre => join('', @pre), 38 | post => join('', @post), 39 | rules => [ map { 40 | $_->{body} = join('', @{$_->{body}}); 41 | $_; 42 | } @rules ] 43 | }; 44 | 45 | use Data::Dumper; 46 | print Dumper($spec); 47 | -------------------------------------------------------------------------------- /lexer-ll/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bql.ll.h" 3 | 4 | int main(int argc, char **argv) { 5 | void *state; 6 | 7 | state = lex_open("l/bql.ll"); 8 | if (!state) { 9 | perror("lex_open"); 10 | return 1; 11 | } 12 | 13 | while (lex(state)) { 14 | // ... 15 | } 16 | 17 | lex_close(state); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /malloc/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | victim 4 | -------------------------------------------------------------------------------- /malloc/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # fmalloc - 3 | # 4 | 5 | all: victim libfmalloc1.so 6 | 7 | victim: victim.c 8 | $(CC) -o $@ $+ 9 | 10 | libfmalloc1.so: fmalloc1.o 11 | $(CC) -shared -Wl,-soname,fmalloc1 -o $@ $+ 12 | 13 | %.o: %.c 14 | $(CC) -fPIC -c -o $@ $+ 15 | 16 | clean: 17 | rm -f fmalloc1.o 18 | rm -f victim 19 | rm -f libfmalloc.so 20 | -------------------------------------------------------------------------------- /malloc/fmalloc1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define puts(x) write(2, (x), strlen(x)) 9 | 10 | static struct { 11 | int init; 12 | int left; 13 | } FMALLOC = {0}; 14 | static int N = -1; 15 | 16 | static inline void __init(void) 17 | { 18 | if (!FMALLOC.init) { 19 | char *s = getenv("MALLOC_OK"); 20 | FMALLOC.left = atoi(s ? s : "-1"); 21 | 22 | FMALLOC.init = 1; 23 | } 24 | } 25 | 26 | static inline int __check(void) 27 | { 28 | if (FMALLOC.left == 0) { 29 | char *sigil = getenv("MALLOC_FS_SIGIL"); 30 | if (sigil) 31 | unlink(sigil); 32 | return 0; 33 | } 34 | 35 | FMALLOC.left--; 36 | return 1; 37 | } 38 | 39 | static inline void* __malloc(size_t n) 40 | { 41 | if (!n) 42 | return NULL; 43 | 44 | void *p = sbrk(0); 45 | void *r = sbrk(n); 46 | if (r == (void*) -1) 47 | return NULL; 48 | 49 | assert(p == r); /* not thread-safe */ 50 | return p; 51 | } 52 | 53 | void* malloc(size_t n) 54 | { 55 | __init(); 56 | return __check() ? __malloc(n) : NULL; 57 | } 58 | 59 | void* calloc(size_t n, size_t each) 60 | { 61 | void *m = malloc(n * each); 62 | if (m) 63 | memset(m, 0, n * each); 64 | return m; 65 | } 66 | 67 | void *realloc(void *p, size_t n) 68 | { 69 | return NULL; 70 | } 71 | -------------------------------------------------------------------------------- /malloc/victim.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main (int argc, char **argv) 5 | { 6 | if (malloc(24) == NULL) 7 | fprintf(stderr, "first malloc failed\n"); 8 | if (malloc(24) == NULL) 9 | fprintf(stderr, "second malloc failed\n"); 10 | if (malloc(24) == NULL) 11 | fprintf(stderr, "third malloc failed\n"); 12 | 13 | if (calloc(48, sizeof(char)) == NULL) 14 | fprintf(stderr, "first calloc failed\n"); 15 | if (calloc(48, sizeof(char)) == NULL) 16 | fprintf(stderr, "second calloc failed\n"); 17 | if (calloc(48, sizeof(char)) == NULL) 18 | fprintf(stderr, "third calloc failed\n"); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /matrix/matrix.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | sub max { 5 | return $_[0] > $_[1] ? $_[0] : $_[1]; 6 | } 7 | 8 | sub similarity { 9 | my ($a, $b, $n) = (0, 0, 0); 10 | my %a = map { $_ => 1 } @{$_[0]}; 11 | delete $a{$_} for keys %{$_[2]}; 12 | $a = scalar keys %a; 13 | for (@{$_[1]}) { 14 | next if $_[2]->{$_}; 15 | $b++; 16 | $n++ if $a{$_}; 17 | } 18 | return $n / max($a, $b); 19 | } 20 | 21 | my %D; 22 | while (<>) { 23 | chomp; 24 | my ($name, @releases) = split /\s+/, $_; 25 | $D{$name} = \@releases; 26 | } 27 | 28 | my $addons = { 'os-conf' => 1 }; 29 | my @names = sort keys %D; 30 | for (my $i = 0; $i < @names; $i++) { 31 | next unless $names[$i]; 32 | my $set = [$names[$i]]; 33 | for (my $j = $i + 1; $j < @names; $j++) { 34 | if (similarity($D{$names[$i]}, $D{$names[$j]}, $addons) > 0.66) { 35 | push @$set, $names[$j]; 36 | $names[$j] = undef; 37 | } 38 | } 39 | print "SET:\n"; 40 | print " - $_\n" for @$set; 41 | print "\n\n"; 42 | } 43 | -------------------------------------------------------------------------------- /matrix/sets: -------------------------------------------------------------------------------- 1 | scs1 os-conf spring-cloud-broker 2 | ops-metrics1 os-conf cf-metrics 3 | gemfire1 os-conf GemFire GemFire-Broker GemFire-Broker-Registrar 4 | gemfire2 os-conf GemFire GemFire-Broker GemFire-Broker-Registrar 5 | gemfire3 os-conf GemFire GemFire-Broker GemFire-Broker-Registrar 6 | bind1 os-conf bind9 7 | cf1 os-conf cf cf-mysql cflinuxfs2-rootfs diego notifications-ui garden-runc mysql-backup mysql-monitoring service-backup etcd notifications cf-autoscaling push-apps-manager-release consul 8 | cf2 os-conf cf cf-mysql cflinuxfs2-rootfs diego notifications-ui garden-runc mysql-backup mysql-monitoring service-backup etcd notifications cf-autoscaling push-apps-manager-release 9 | concourse1 os-conf concourse garden-runc os-conf 10 | concourse2 os-conf concourse garden-runc os-conf 11 | concourse3 os-conf concourse garden-runc os-conf 12 | -------------------------------------------------------------------------------- /mlock/.gitignore: -------------------------------------------------------------------------------- 1 | /mlock 2 | -------------------------------------------------------------------------------- /mlock/mlock.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | return (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) ? 0 : 1; 6 | } 7 | -------------------------------------------------------------------------------- /nacl/.gitignore: -------------------------------------------------------------------------------- 1 | /encrypt 2 | /decrypt 3 | /decrypt2 4 | /decrypt3 5 | -------------------------------------------------------------------------------- /nacl/Makefile: -------------------------------------------------------------------------------- 1 | BINS := 2 | BINS += encrypt 3 | BINS += decrypt 4 | BINS += decrypt2 5 | BINS += decrypt3 6 | 7 | default: $(BINS) 8 | clean: 9 | rm -f tweetnacl.o $(BINS:=.o) $(BINS) 10 | 11 | encrypt: encrypt.o tweetnacl.o 12 | decrypt: decrypt.o tweetnacl.o 13 | decrypt2: decrypt2.o tweetnacl.o 14 | decrypt3: decrypt3.o tweetnacl.o 15 | -------------------------------------------------------------------------------- /nacl/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "tweetnacl.h" 10 | 11 | #define MESSAGE "There are strange things done in the midnight sun\n" \ 12 | "By the men who toil for gold;\n" \ 13 | "The Arctic trails have their secret tales\n" \ 14 | "That would make your blood run cold;\n" \ 15 | "The Northern Lights have seen queer sights,\n" \ 16 | "But the queerest they ever did see\n" \ 17 | "Was that night on the marge of Lake Lebarge\n" \ 18 | "I cremated Sam McGee.\n" 19 | /* - Robert W. Service */ 20 | 21 | #define MESSAGE_LEN 304 /* I counted */ 22 | 23 | /* generated by crypto_box_keypair() */ 24 | #define CLIENT_PUB "\xbc\x07\x9f\xfe\xf5\x09\x6b\x2b" \ 25 | "\xfe\xd3\x8e\xdb\xe5\x26\xc0\xd3" \ 26 | "\x57\xba\x79\x88\xbf\xff\x9e\x8e" \ 27 | "\xea\x85\xcf\xd4\xcb\xb0\x7b\x3d" 28 | 29 | #define CLIENT_SEC "\x53\xb7\xab\xca\x19\x81\xca\xd7" \ 30 | "\x6a\x87\x9d\xe3\xa3\x93\xd5\x73" \ 31 | "\x84\x39\xa5\x10\x3e\x4d\xdf\xde" \ 32 | "\xea\x19\x25\x01\xc9\xf3\x06\xf6" 33 | 34 | 35 | /* also generated by crypto_box_keypair() */ 36 | #define SERVER_PUB "\xb0\x5c\x49\xda\xc9\xf6\xbc\x86" \ 37 | "\xcf\x76\xe5\xbd\xca\xe8\x0e\x14" \ 38 | "\x50\x03\xba\xbb\xa9\x4d\xfc\x6c" \ 39 | "\x4c\x0a\xeb\xff\x9a\x5c\xba\x31" 40 | 41 | #define SERVER_SEC "\x22\x1b\x3e\x9c\xf7\xb0\x94\xdd" \ 42 | "\xec\xdb\x58\x02\x4f\x54\xa6\xfa" \ 43 | "\xc9\x0f\xa4\x86\x90\x80\xe7\xf5" \ 44 | "\xec\xb9\x4d\x87\xdb\xb9\x1e\xfc" 45 | 46 | static void 47 | dump(const char *prefix, const uint8_t *buf, size_t len) 48 | { 49 | size_t i; 50 | printf("%s\n------------------------------------------------\n", prefix); 51 | for (i = 0; i < len; i++) { 52 | printf(" %02x%s", buf[i], (i+1) % 16 == 0 ? "\n" : ""); 53 | } 54 | if (len % 16 != 0) printf("\n"); 55 | printf("------------------------------------------------\n"); 56 | } 57 | 58 | /* tweetnacl is a bring-your-own-randomness kinda lib */ 59 | int 60 | randombytes(uint8_t *buf, size_t len) 61 | { 62 | FILE *in; 63 | int rc; 64 | in = fopen("/dev/urandom", "r"); 65 | if (!in) return 1; 66 | rc = fread(buf, len, 1, in) == 1 ? 0 : 1; 67 | fclose(in); 68 | return rc; 69 | } 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /nacl/decrypt.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | /* NOTE: this example is expected to fail, because I screwed up 4 | the padding. On purpose. Read the blog post for more: 5 | 6 | http://jameshunt.us/writings/nacl-padding.html 7 | */ 8 | int main(int argc, char **argv) 9 | { 10 | int rc; 11 | uint8_t client_pub[32], client_sec[32]; 12 | uint8_t server_pub[32], server_sec[32]; 13 | uint8_t cipher[512], plain[512]; 14 | uint8_t nonce[24]; 15 | 16 | /* initialize memory */ 17 | memset(cipher, 0, 512); 18 | memset(plain, 0, 512); 19 | 20 | /* "generate" nonce */ 21 | memset(nonce, 0, 24); 22 | 23 | /* "generate" keys */ 24 | memcpy(client_pub, CLIENT_PUB, 32); 25 | memcpy(client_sec, CLIENT_SEC, 32); 26 | memcpy(server_pub, SERVER_PUB, 32); 27 | memcpy(server_sec, SERVER_SEC, 32); 28 | 29 | /* assemble plaintext */ 30 | memcpy(plain, MESSAGE, MESSAGE_LEN); 31 | dump("plaintext, before encryption", plain, MESSAGE_LEN); 32 | 33 | /* encipher message from client to server */ 34 | rc = crypto_box(cipher, plain, MESSAGE_LEN, 35 | nonce, server_pub, client_sec); 36 | dump("ciphertext", cipher, MESSAGE_LEN); 37 | assert(rc == 0); 38 | 39 | /* erase all trace of plaintext */ 40 | memset(plain, 0, 512); 41 | 42 | /* decipher message as server, using client's public key */ 43 | rc = crypto_box_open(plain, cipher, MESSAGE_LEN, 44 | nonce, client_pub, server_sec); 45 | dump("plaintext, after decryption", plain, MESSAGE_LEN); 46 | assert(rc == 0); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /nacl/decrypt2.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | /* NOTE: this example is expected to fail, because I screwed up 4 | the padding. On purpose. Read the blog post for more: 5 | 6 | http://jameshunt.us/writings/nacl-padding.html 7 | */ 8 | 9 | int main(int argc, char **argv) 10 | { 11 | int rc; 12 | uint8_t client_pub[32], client_sec[32]; 13 | uint8_t server_pub[32], server_sec[32]; 14 | uint8_t cipher[512], plain[512]; 15 | uint8_t nonce[24]; 16 | 17 | /* initialize memory */ 18 | memset(cipher, 0, 512); 19 | memset(plain, 0, 512); 20 | 21 | /* "generate" nonce */ 22 | memset(nonce, 0, 24); 23 | 24 | /* "generate" keys */ 25 | memcpy(client_pub, CLIENT_PUB, 32); 26 | memcpy(client_sec, CLIENT_SEC, 32); 27 | memcpy(server_pub, SERVER_PUB, 32); 28 | memcpy(server_sec, SERVER_SEC, 32); 29 | 30 | /* assemble plaintext */ 31 | memset(plain, 0, 32); /* first 32 octest are ZERO */ 32 | memcpy(plain+32, MESSAGE, MESSAGE_LEN); /* then comes the real data */ 33 | dump("plaintext, before encryption", plain, MESSAGE_LEN+32); 34 | 35 | /* encipher message from client to server */ 36 | rc = crypto_box(cipher, plain, MESSAGE_LEN+32, 37 | nonce, server_pub, client_sec); 38 | dump("ciphertext", cipher, MESSAGE_LEN); 39 | assert(rc == 0); 40 | 41 | /* erase all trace of plaintext */ 42 | memset(plain, 0, 512); 43 | 44 | /* decipher message as server, using client's public key */ 45 | rc = crypto_box_open(plain, cipher, MESSAGE_LEN+32, 46 | nonce, client_pub, server_sec); 47 | dump("plaintext, after decryption", plain, MESSAGE_LEN+32); 48 | assert(rc == 0); 49 | assert(memcmp(MESSAGE, plain, MESSAGE_LEN) == 0); 50 | 51 | plain[MESSAGE_LEN+1] = '\0'; 52 | printf("%s\n", plain); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /nacl/decrypt3.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | /* NOTE: this example will work! Read the blog post for more: 4 | 5 | http://jameshunt.us/writings/nacl-padding.html 6 | */ 7 | 8 | int main(int argc, char **argv) 9 | { 10 | int rc; 11 | uint8_t client_pub[32], client_sec[32]; 12 | uint8_t server_pub[32], server_sec[32]; 13 | uint8_t cipher[512], plain[512]; 14 | uint8_t nonce[24]; 15 | 16 | /* initialize memory */ 17 | memset(cipher, 0, 512); 18 | memset(plain, 0, 512); 19 | 20 | /* "generate" nonce */ 21 | memset(nonce, 0, 24); 22 | 23 | /* "generate" keys */ 24 | memcpy(client_pub, CLIENT_PUB, 32); 25 | memcpy(client_sec, CLIENT_SEC, 32); 26 | memcpy(server_pub, SERVER_PUB, 32); 27 | memcpy(server_sec, SERVER_SEC, 32); 28 | 29 | /* assemble plaintext */ 30 | memset(plain, 0, 32); /* first 32 octest are ZERO */ 31 | memcpy(plain+32, MESSAGE, MESSAGE_LEN); /* then comes the real data */ 32 | dump("plaintext, before encryption", plain, MESSAGE_LEN+32); 33 | 34 | /* encipher message from client to server */ 35 | rc = crypto_box(cipher, plain, MESSAGE_LEN+32, 36 | nonce, server_pub, client_sec); 37 | dump("ciphertext", cipher, MESSAGE_LEN+32); 38 | assert(rc == 0); 39 | 40 | /* erase all trace of plaintext */ 41 | memset(plain, 0, 512); 42 | 43 | /* decipher message as server, using client's public key */ 44 | rc = crypto_box_open(plain, cipher, MESSAGE_LEN+32, 45 | nonce, client_pub, server_sec); 46 | assert(rc == 0); 47 | memmove(plain, plain+32, MESSAGE_LEN); 48 | dump("plaintext, after decryption", plain, MESSAGE_LEN); 49 | assert(memcmp(MESSAGE, plain, MESSAGE_LEN) == 0); 50 | 51 | plain[MESSAGE_LEN] = '\0'; 52 | printf("\n%s\n", plain); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /nacl/encrypt.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | /* NOTE: this example is expected "succeeds", but without attempting 4 | to decrypt the resulting ciphertext, we can't quite count it 5 | a success just yet. Read the blog post for more: 6 | 7 | http://jameshunt.us/writings/nacl-padding.html 8 | */ 9 | 10 | int main(int argc, char **argv) 11 | { 12 | int rc; 13 | uint8_t client_pub[32], client_sec[32]; 14 | uint8_t server_pub[32], server_sec[32]; 15 | uint8_t cipher[512], plain[512]; 16 | uint8_t nonce[24]; 17 | 18 | /* initialize memory */ 19 | memset(cipher, 0, 512); 20 | memset(plain, 0, 512); 21 | 22 | /* "generate" nonce */ 23 | memset(nonce, 0, 24); 24 | 25 | /* "generate" keys */ 26 | memcpy(client_pub, CLIENT_PUB, 32); 27 | memcpy(client_sec, CLIENT_SEC, 32); 28 | memcpy(server_pub, SERVER_PUB, 32); 29 | memcpy(server_sec, SERVER_SEC, 32); 30 | 31 | /* assemble plaintext */ 32 | memcpy(plain, MESSAGE, MESSAGE_LEN); 33 | dump("plaintext, before encryption", plain, MESSAGE_LEN); 34 | 35 | /* encipher message from client to server */ 36 | rc = crypto_box(cipher, plain, MESSAGE_LEN, 37 | nonce, server_pub, client_sec); 38 | dump("ciphertext", cipher, MESSAGE_LEN); 39 | assert(rc == 0); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /nacl/tweetnacl.c: -------------------------------------------------------------------------------- 1 | #include "tweetnacl.h" 2 | #define FOR(i,n) for (i = 0;i < n;++i) 3 | #define sv static void 4 | 5 | typedef unsigned char u8; 6 | typedef unsigned long u32; 7 | typedef unsigned long long u64; 8 | typedef long long i64; 9 | typedef i64 gf[16]; 10 | extern void randombytes(u8 *,u64); 11 | 12 | static const u8 13 | _0[16], 14 | _9[32] = {9}; 15 | static const gf 16 | gf0, 17 | gf1 = {1}, 18 | _121665 = {0xDB41,1}, 19 | D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203}, 20 | D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406}, 21 | X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169}, 22 | Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666}, 23 | I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83}; 24 | 25 | static u32 L32(u32 x,int c) { return (x << c) | ((x&0xffffffff) >> (32 - c)); } 26 | 27 | static u32 ld32(const u8 *x) 28 | { 29 | u32 u = x[3]; 30 | u = (u<<8)|x[2]; 31 | u = (u<<8)|x[1]; 32 | return (u<<8)|x[0]; 33 | } 34 | 35 | static u64 dl64(const u8 *x) 36 | { 37 | u64 i,u=0; 38 | FOR(i,8) u=(u<<8)|x[i]; 39 | return u; 40 | } 41 | 42 | sv st32(u8 *x,u32 u) 43 | { 44 | int i; 45 | FOR(i,4) { x[i] = u; u >>= 8; } 46 | } 47 | 48 | sv ts64(u8 *x,u64 u) 49 | { 50 | int i; 51 | for (i = 7;i >= 0;--i) { x[i] = u; u >>= 8; } 52 | } 53 | 54 | static int vn(const u8 *x,const u8 *y,int n) 55 | { 56 | u32 i,d = 0; 57 | FOR(i,n) d |= x[i]^y[i]; 58 | return (1 & ((d - 1) >> 8)) - 1; 59 | } 60 | 61 | int crypto_verify_16(const u8 *x,const u8 *y) 62 | { 63 | return vn(x,y,16); 64 | } 65 | 66 | int crypto_verify_32(const u8 *x,const u8 *y) 67 | { 68 | return vn(x,y,32); 69 | } 70 | 71 | sv core(u8 *out,const u8 *in,const u8 *k,const u8 *c,int h) 72 | { 73 | u32 w[16],x[16],y[16],t[4]; 74 | int i,j,m; 75 | 76 | FOR(i,4) { 77 | x[5*i] = ld32(c+4*i); 78 | x[1+i] = ld32(k+4*i); 79 | x[6+i] = ld32(in+4*i); 80 | x[11+i] = ld32(k+16+4*i); 81 | } 82 | 83 | FOR(i,16) y[i] = x[i]; 84 | 85 | FOR(i,20) { 86 | FOR(j,4) { 87 | FOR(m,4) t[m] = x[(5*j+4*m)%16]; 88 | t[1] ^= L32(t[0]+t[3], 7); 89 | t[2] ^= L32(t[1]+t[0], 9); 90 | t[3] ^= L32(t[2]+t[1],13); 91 | t[0] ^= L32(t[3]+t[2],18); 92 | FOR(m,4) w[4*j+(j+m)%4] = t[m]; 93 | } 94 | FOR(m,16) x[m] = w[m]; 95 | } 96 | 97 | if (h) { 98 | FOR(i,16) x[i] += y[i]; 99 | FOR(i,4) { 100 | x[5*i] -= ld32(c+4*i); 101 | x[6+i] -= ld32(in+4*i); 102 | } 103 | FOR(i,4) { 104 | st32(out+4*i,x[5*i]); 105 | st32(out+16+4*i,x[6+i]); 106 | } 107 | } else 108 | FOR(i,16) st32(out + 4 * i,x[i] + y[i]); 109 | } 110 | 111 | int crypto_core_salsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c) 112 | { 113 | core(out,in,k,c,0); 114 | return 0; 115 | } 116 | 117 | int crypto_core_hsalsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c) 118 | { 119 | core(out,in,k,c,1); 120 | return 0; 121 | } 122 | 123 | static const u8 sigma[16] = "expand 32-byte k"; 124 | 125 | int crypto_stream_salsa20_xor(u8 *c,const u8 *m,u64 b,const u8 *n,const u8 *k) 126 | { 127 | u8 z[16],x[64]; 128 | u32 u,i; 129 | if (!b) return 0; 130 | FOR(i,16) z[i] = 0; 131 | FOR(i,8) z[i] = n[i]; 132 | while (b >= 64) { 133 | crypto_core_salsa20(x,z,k,sigma); 134 | FOR(i,64) c[i] = (m?m[i]:0) ^ x[i]; 135 | u = 1; 136 | for (i = 8;i < 16;++i) { 137 | u += (u32) z[i]; 138 | z[i] = u; 139 | u >>= 8; 140 | } 141 | b -= 64; 142 | c += 64; 143 | if (m) m += 64; 144 | } 145 | if (b) { 146 | crypto_core_salsa20(x,z,k,sigma); 147 | FOR(i,b) c[i] = (m?m[i]:0) ^ x[i]; 148 | } 149 | return 0; 150 | } 151 | 152 | int crypto_stream_salsa20(u8 *c,u64 d,const u8 *n,const u8 *k) 153 | { 154 | return crypto_stream_salsa20_xor(c,0,d,n,k); 155 | } 156 | 157 | int crypto_stream(u8 *c,u64 d,const u8 *n,const u8 *k) 158 | { 159 | u8 s[32]; 160 | crypto_core_hsalsa20(s,n,k,sigma); 161 | return crypto_stream_salsa20(c,d,n+16,s); 162 | } 163 | 164 | int crypto_stream_xor(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) 165 | { 166 | u8 s[32]; 167 | crypto_core_hsalsa20(s,n,k,sigma); 168 | return crypto_stream_salsa20_xor(c,m,d,n+16,s); 169 | } 170 | 171 | sv add1305(u32 *h,const u32 *c) 172 | { 173 | u32 j,u = 0; 174 | FOR(j,17) { 175 | u += h[j] + c[j]; 176 | h[j] = u & 255; 177 | u >>= 8; 178 | } 179 | } 180 | 181 | static const u32 minusp[17] = { 182 | 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252 183 | } ; 184 | 185 | int crypto_onetimeauth(u8 *out,const u8 *m,u64 n,const u8 *k) 186 | { 187 | u32 s,i,j,u,x[17],r[17],h[17],c[17],g[17]; 188 | 189 | FOR(j,17) r[j]=h[j]=0; 190 | FOR(j,16) r[j]=k[j]; 191 | r[3]&=15; 192 | r[4]&=252; 193 | r[7]&=15; 194 | r[8]&=252; 195 | r[11]&=15; 196 | r[12]&=252; 197 | r[15]&=15; 198 | 199 | while (n > 0) { 200 | FOR(j,17) c[j] = 0; 201 | for (j = 0;(j < 16) && (j < n);++j) c[j] = m[j]; 202 | c[j] = 1; 203 | m += j; n -= j; 204 | add1305(h,c); 205 | FOR(i,17) { 206 | x[i] = 0; 207 | FOR(j,17) x[i] += h[j] * ((j <= i) ? r[i - j] : 320 * r[i + 17 - j]); 208 | } 209 | FOR(i,17) h[i] = x[i]; 210 | u = 0; 211 | FOR(j,16) { 212 | u += h[j]; 213 | h[j] = u & 255; 214 | u >>= 8; 215 | } 216 | u += h[16]; h[16] = u & 3; 217 | u = 5 * (u >> 2); 218 | FOR(j,16) { 219 | u += h[j]; 220 | h[j] = u & 255; 221 | u >>= 8; 222 | } 223 | u += h[16]; h[16] = u; 224 | } 225 | 226 | FOR(j,17) g[j] = h[j]; 227 | add1305(h,minusp); 228 | s = -(h[16] >> 7); 229 | FOR(j,17) h[j] ^= s & (g[j] ^ h[j]); 230 | 231 | FOR(j,16) c[j] = k[j + 16]; 232 | c[16] = 0; 233 | add1305(h,c); 234 | FOR(j,16) out[j] = h[j]; 235 | return 0; 236 | } 237 | 238 | int crypto_onetimeauth_verify(const u8 *h,const u8 *m,u64 n,const u8 *k) 239 | { 240 | u8 x[16]; 241 | crypto_onetimeauth(x,m,n,k); 242 | return crypto_verify_16(h,x); 243 | } 244 | 245 | int crypto_secretbox(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) 246 | { 247 | int i; 248 | if (d < 32) return -1; 249 | crypto_stream_xor(c,m,d,n,k); 250 | crypto_onetimeauth(c + 16,c + 32,d - 32,c); 251 | FOR(i,16) c[i] = 0; 252 | return 0; 253 | } 254 | 255 | int crypto_secretbox_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k) 256 | { 257 | int i; 258 | u8 x[32]; 259 | if (d < 32) return -1; 260 | crypto_stream(x,32,n,k); 261 | if (crypto_onetimeauth_verify(c + 16,c + 32,d - 32,x) != 0) return -1; 262 | crypto_stream_xor(m,c,d,n,k); 263 | FOR(i,32) m[i] = 0; 264 | return 0; 265 | } 266 | 267 | sv set25519(gf r, const gf a) 268 | { 269 | int i; 270 | FOR(i,16) r[i]=a[i]; 271 | } 272 | 273 | sv car25519(gf o) 274 | { 275 | int i; 276 | i64 c; 277 | FOR(i,16) { 278 | o[i]+=(1LL<<16); 279 | c=o[i]>>16; 280 | o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15); 281 | o[i]-=c<<16; 282 | } 283 | } 284 | 285 | sv sel25519(gf p,gf q,int b) 286 | { 287 | i64 t,i,c=~(b-1); 288 | FOR(i,16) { 289 | t= c&(p[i]^q[i]); 290 | p[i]^=t; 291 | q[i]^=t; 292 | } 293 | } 294 | 295 | sv pack25519(u8 *o,const gf n) 296 | { 297 | int i,j,b; 298 | gf m,t; 299 | FOR(i,16) t[i]=n[i]; 300 | car25519(t); 301 | car25519(t); 302 | car25519(t); 303 | FOR(j,2) { 304 | m[0]=t[0]-0xffed; 305 | for(i=1;i<15;i++) { 306 | m[i]=t[i]-0xffff-((m[i-1]>>16)&1); 307 | m[i-1]&=0xffff; 308 | } 309 | m[15]=t[15]-0x7fff-((m[14]>>16)&1); 310 | b=(m[15]>>16)&1; 311 | m[14]&=0xffff; 312 | sel25519(t,m,1-b); 313 | } 314 | FOR(i,16) { 315 | o[2*i]=t[i]&0xff; 316 | o[2*i+1]=t[i]>>8; 317 | } 318 | } 319 | 320 | static int neq25519(const gf a, const gf b) 321 | { 322 | u8 c[32],d[32]; 323 | pack25519(c,a); 324 | pack25519(d,b); 325 | return crypto_verify_32(c,d); 326 | } 327 | 328 | static u8 par25519(const gf a) 329 | { 330 | u8 d[32]; 331 | pack25519(d,a); 332 | return d[0]&1; 333 | } 334 | 335 | sv unpack25519(gf o, const u8 *n) 336 | { 337 | int i; 338 | FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8); 339 | o[15]&=0x7fff; 340 | } 341 | 342 | sv A(gf o,const gf a,const gf b) 343 | { 344 | int i; 345 | FOR(i,16) o[i]=a[i]+b[i]; 346 | } 347 | 348 | sv Z(gf o,const gf a,const gf b) 349 | { 350 | int i; 351 | FOR(i,16) o[i]=a[i]-b[i]; 352 | } 353 | 354 | sv M(gf o,const gf a,const gf b) 355 | { 356 | i64 i,j,t[31]; 357 | FOR(i,31) t[i]=0; 358 | FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j]; 359 | FOR(i,15) t[i]+=38*t[i+16]; 360 | FOR(i,16) o[i]=t[i]; 361 | car25519(o); 362 | car25519(o); 363 | } 364 | 365 | sv S(gf o,const gf a) 366 | { 367 | M(o,a,a); 368 | } 369 | 370 | sv inv25519(gf o,const gf i) 371 | { 372 | gf c; 373 | int a; 374 | FOR(a,16) c[a]=i[a]; 375 | for(a=253;a>=0;a--) { 376 | S(c,c); 377 | if(a!=2&&a!=4) M(c,c,i); 378 | } 379 | FOR(a,16) o[a]=c[a]; 380 | } 381 | 382 | sv pow2523(gf o,const gf i) 383 | { 384 | gf c; 385 | int a; 386 | FOR(a,16) c[a]=i[a]; 387 | for(a=250;a>=0;a--) { 388 | S(c,c); 389 | if(a!=1) M(c,c,i); 390 | } 391 | FOR(a,16) o[a]=c[a]; 392 | } 393 | 394 | int crypto_scalarmult(u8 *q,const u8 *n,const u8 *p) 395 | { 396 | u8 z[32]; 397 | i64 x[80],r,i; 398 | gf a,b,c,d,e,f; 399 | FOR(i,31) z[i]=n[i]; 400 | z[31]=(n[31]&127)|64; 401 | z[0]&=248; 402 | unpack25519(x,p); 403 | FOR(i,16) { 404 | b[i]=x[i]; 405 | d[i]=a[i]=c[i]=0; 406 | } 407 | a[0]=d[0]=1; 408 | for(i=254;i>=0;--i) { 409 | r=(z[i>>3]>>(i&7))&1; 410 | sel25519(a,b,r); 411 | sel25519(c,d,r); 412 | A(e,a,c); 413 | Z(a,a,c); 414 | A(c,b,d); 415 | Z(b,b,d); 416 | S(d,e); 417 | S(f,a); 418 | M(a,c,a); 419 | M(c,b,e); 420 | A(e,a,c); 421 | Z(a,a,c); 422 | S(b,a); 423 | Z(c,d,f); 424 | M(a,c,_121665); 425 | A(a,a,d); 426 | M(c,c,a); 427 | M(a,d,f); 428 | M(d,b,x); 429 | S(b,e); 430 | sel25519(a,b,r); 431 | sel25519(c,d,r); 432 | } 433 | FOR(i,16) { 434 | x[i+16]=a[i]; 435 | x[i+32]=c[i]; 436 | x[i+48]=b[i]; 437 | x[i+64]=d[i]; 438 | } 439 | inv25519(x+32,x+32); 440 | M(x+16,x+16,x+32); 441 | pack25519(q,x+16); 442 | return 0; 443 | } 444 | 445 | int crypto_scalarmult_base(u8 *q,const u8 *n) 446 | { 447 | return crypto_scalarmult(q,n,_9); 448 | } 449 | 450 | int crypto_box_keypair(u8 *y,u8 *x) 451 | { 452 | randombytes(x,32); 453 | return crypto_scalarmult_base(y,x); 454 | } 455 | 456 | int crypto_box_beforenm(u8 *k,const u8 *y,const u8 *x) 457 | { 458 | u8 s[32]; 459 | crypto_scalarmult(s,x,y); 460 | return crypto_core_hsalsa20(k,_0,s,sigma); 461 | } 462 | 463 | int crypto_box_afternm(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) 464 | { 465 | return crypto_secretbox(c,m,d,n,k); 466 | } 467 | 468 | int crypto_box_open_afternm(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k) 469 | { 470 | return crypto_secretbox_open(m,c,d,n,k); 471 | } 472 | 473 | int crypto_box(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *y,const u8 *x) 474 | { 475 | u8 k[32]; 476 | crypto_box_beforenm(k,y,x); 477 | return crypto_box_afternm(c,m,d,n,k); 478 | } 479 | 480 | int crypto_box_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *y,const u8 *x) 481 | { 482 | u8 k[32]; 483 | crypto_box_beforenm(k,y,x); 484 | return crypto_box_open_afternm(m,c,d,n,k); 485 | } 486 | 487 | static u64 R(u64 x,int c) { return (x >> c) | (x << (64 - c)); } 488 | static u64 Ch(u64 x,u64 y,u64 z) { return (x & y) ^ (~x & z); } 489 | static u64 Maj(u64 x,u64 y,u64 z) { return (x & y) ^ (x & z) ^ (y & z); } 490 | static u64 Sigma0(u64 x) { return R(x,28) ^ R(x,34) ^ R(x,39); } 491 | static u64 Sigma1(u64 x) { return R(x,14) ^ R(x,18) ^ R(x,41); } 492 | static u64 sigma0(u64 x) { return R(x, 1) ^ R(x, 8) ^ (x >> 7); } 493 | static u64 sigma1(u64 x) { return R(x,19) ^ R(x,61) ^ (x >> 6); } 494 | 495 | static const u64 K[80] = 496 | { 497 | 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 498 | 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 499 | 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 500 | 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 501 | 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 502 | 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 503 | 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 504 | 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 505 | 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 506 | 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 507 | 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 508 | 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 509 | 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 510 | 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 511 | 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 512 | 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 513 | 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 514 | 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 515 | 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 516 | 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL 517 | }; 518 | 519 | int crypto_hashblocks(u8 *x,const u8 *m,u64 n) 520 | { 521 | u64 z[8],b[8],a[8],w[16],t; 522 | int i,j; 523 | 524 | FOR(i,8) z[i] = a[i] = dl64(x + 8 * i); 525 | 526 | while (n >= 128) { 527 | FOR(i,16) w[i] = dl64(m + 8 * i); 528 | 529 | FOR(i,80) { 530 | FOR(j,8) b[j] = a[j]; 531 | t = a[7] + Sigma1(a[4]) + Ch(a[4],a[5],a[6]) + K[i] + w[i%16]; 532 | b[7] = t + Sigma0(a[0]) + Maj(a[0],a[1],a[2]); 533 | b[3] += t; 534 | FOR(j,8) a[(j+1)%8] = b[j]; 535 | if (i%16 == 15) 536 | FOR(j,16) 537 | w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]); 538 | } 539 | 540 | FOR(i,8) { a[i] += z[i]; z[i] = a[i]; } 541 | 542 | m += 128; 543 | n -= 128; 544 | } 545 | 546 | FOR(i,8) ts64(x+8*i,z[i]); 547 | 548 | return n; 549 | } 550 | 551 | static const u8 iv[64] = { 552 | 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, 553 | 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, 554 | 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, 555 | 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, 556 | 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, 557 | 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, 558 | 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, 559 | 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 560 | } ; 561 | 562 | int crypto_hash(u8 *out,const u8 *m,u64 n) 563 | { 564 | u8 h[64],x[256]; 565 | u64 i,b = n; 566 | 567 | FOR(i,64) h[i] = iv[i]; 568 | 569 | crypto_hashblocks(h,m,n); 570 | m += n; 571 | n &= 127; 572 | m -= n; 573 | 574 | FOR(i,256) x[i] = 0; 575 | FOR(i,n) x[i] = m[i]; 576 | x[n] = 128; 577 | 578 | n = 256-128*(n<112); 579 | x[n-9] = b >> 61; 580 | ts64(x+n-8,b<<3); 581 | crypto_hashblocks(h,x,n); 582 | 583 | FOR(i,64) out[i] = h[i]; 584 | 585 | return 0; 586 | } 587 | 588 | sv add(gf p[4],gf q[4]) 589 | { 590 | gf a,b,c,d,t,e,f,g,h; 591 | 592 | Z(a, p[1], p[0]); 593 | Z(t, q[1], q[0]); 594 | M(a, a, t); 595 | A(b, p[0], p[1]); 596 | A(t, q[0], q[1]); 597 | M(b, b, t); 598 | M(c, p[3], q[3]); 599 | M(c, c, D2); 600 | M(d, p[2], q[2]); 601 | A(d, d, d); 602 | Z(e, b, a); 603 | Z(f, d, c); 604 | A(g, d, c); 605 | A(h, b, a); 606 | 607 | M(p[0], e, f); 608 | M(p[1], h, g); 609 | M(p[2], g, f); 610 | M(p[3], e, h); 611 | } 612 | 613 | sv cswap(gf p[4],gf q[4],u8 b) 614 | { 615 | int i; 616 | FOR(i,4) 617 | sel25519(p[i],q[i],b); 618 | } 619 | 620 | sv pack(u8 *r,gf p[4]) 621 | { 622 | gf tx, ty, zi; 623 | inv25519(zi, p[2]); 624 | M(tx, p[0], zi); 625 | M(ty, p[1], zi); 626 | pack25519(r, ty); 627 | r[31] ^= par25519(tx) << 7; 628 | } 629 | 630 | sv scalarmult(gf p[4],gf q[4],const u8 *s) 631 | { 632 | int i; 633 | set25519(p[0],gf0); 634 | set25519(p[1],gf1); 635 | set25519(p[2],gf1); 636 | set25519(p[3],gf0); 637 | for (i = 255;i >= 0;--i) { 638 | u8 b = (s[i/8]>>(i&7))&1; 639 | cswap(p,q,b); 640 | add(q,p); 641 | add(p,p); 642 | cswap(p,q,b); 643 | } 644 | } 645 | 646 | sv scalarbase(gf p[4],const u8 *s) 647 | { 648 | gf q[4]; 649 | set25519(q[0],X); 650 | set25519(q[1],Y); 651 | set25519(q[2],gf1); 652 | M(q[3],X,Y); 653 | scalarmult(p,q,s); 654 | } 655 | 656 | int crypto_sign_keypair(u8 *pk, u8 *sk) 657 | { 658 | u8 d[64]; 659 | gf p[4]; 660 | int i; 661 | 662 | randombytes(sk, 32); 663 | crypto_hash(d, sk, 32); 664 | d[0] &= 248; 665 | d[31] &= 127; 666 | d[31] |= 64; 667 | 668 | scalarbase(p,d); 669 | pack(pk,p); 670 | 671 | FOR(i,32) sk[32 + i] = pk[i]; 672 | return 0; 673 | } 674 | 675 | static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10}; 676 | 677 | sv modL(u8 *r,i64 x[64]) 678 | { 679 | i64 carry,i,j; 680 | for (i = 63;i >= 32;--i) { 681 | carry = 0; 682 | for (j = i - 32;j < i - 12;++j) { 683 | x[j] += carry - 16 * x[i] * L[j - (i - 32)]; 684 | carry = (x[j] + 128) >> 8; 685 | x[j] -= carry << 8; 686 | } 687 | x[j] += carry; 688 | x[i] = 0; 689 | } 690 | carry = 0; 691 | FOR(j,32) { 692 | x[j] += carry - (x[31] >> 4) * L[j]; 693 | carry = x[j] >> 8; 694 | x[j] &= 255; 695 | } 696 | FOR(j,32) x[j] -= carry * L[j]; 697 | FOR(i,32) { 698 | x[i+1] += x[i] >> 8; 699 | r[i] = x[i] & 255; 700 | } 701 | } 702 | 703 | sv reduce(u8 *r) 704 | { 705 | i64 x[64],i; 706 | FOR(i,64) x[i] = (u64) r[i]; 707 | FOR(i,64) r[i] = 0; 708 | modL(r,x); 709 | } 710 | 711 | int crypto_sign(u8 *sm,u64 *smlen,const u8 *m,u64 n,const u8 *sk) 712 | { 713 | u8 d[64],h[64],r[64]; 714 | i64 i,j,x[64]; 715 | gf p[4]; 716 | 717 | crypto_hash(d, sk, 32); 718 | d[0] &= 248; 719 | d[31] &= 127; 720 | d[31] |= 64; 721 | 722 | *smlen = n+64; 723 | FOR(i,n) sm[64 + i] = m[i]; 724 | FOR(i,32) sm[32 + i] = d[32 + i]; 725 | 726 | crypto_hash(r, sm+32, n+32); 727 | reduce(r); 728 | scalarbase(p,r); 729 | pack(sm,p); 730 | 731 | FOR(i,32) sm[i+32] = sk[i+32]; 732 | crypto_hash(h,sm,n + 64); 733 | reduce(h); 734 | 735 | FOR(i,64) x[i] = 0; 736 | FOR(i,32) x[i] = (u64) r[i]; 737 | FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j]; 738 | modL(sm + 32,x); 739 | 740 | return 0; 741 | } 742 | 743 | static int unpackneg(gf r[4],const u8 p[32]) 744 | { 745 | gf t, chk, num, den, den2, den4, den6; 746 | set25519(r[2],gf1); 747 | unpack25519(r[1],p); 748 | S(num,r[1]); 749 | M(den,num,D); 750 | Z(num,num,r[2]); 751 | A(den,r[2],den); 752 | 753 | S(den2,den); 754 | S(den4,den2); 755 | M(den6,den4,den2); 756 | M(t,den6,num); 757 | M(t,t,den); 758 | 759 | pow2523(t,t); 760 | M(t,t,num); 761 | M(t,t,den); 762 | M(t,t,den); 763 | M(r[0],t,den); 764 | 765 | S(chk,r[0]); 766 | M(chk,chk,den); 767 | if (neq25519(chk, num)) M(r[0],r[0],I); 768 | 769 | S(chk,r[0]); 770 | M(chk,chk,den); 771 | if (neq25519(chk, num)) return -1; 772 | 773 | if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]); 774 | 775 | M(r[3],r[0],r[1]); 776 | return 0; 777 | } 778 | 779 | int crypto_sign_open(u8 *m,u64 *mlen,const u8 *sm,u64 n,const u8 *pk) 780 | { 781 | int i; 782 | u8 t[32],h[64]; 783 | gf p[4],q[4]; 784 | 785 | *mlen = -1; 786 | if (n < 64) return -1; 787 | 788 | if (unpackneg(q,pk)) return -1; 789 | 790 | FOR(i,n) m[i] = sm[i]; 791 | FOR(i,32) m[i+32] = pk[i]; 792 | crypto_hash(h,m,n); 793 | reduce(h); 794 | scalarmult(p,q,h); 795 | 796 | scalarbase(q,sm + 32); 797 | add(p,q); 798 | pack(t,p); 799 | 800 | n -= 64; 801 | if (crypto_verify_32(sm, t)) { 802 | FOR(i,n) m[i] = 0; 803 | return -1; 804 | } 805 | 806 | FOR(i,n) m[i] = sm[i + 64]; 807 | *mlen = n; 808 | return 0; 809 | } 810 | -------------------------------------------------------------------------------- /nacl/tweetnacl.h: -------------------------------------------------------------------------------- 1 | #ifndef TWEETNACL_H 2 | #define TWEETNACL_H 3 | #define crypto_auth_PRIMITIVE "hmacsha512256" 4 | #define crypto_auth crypto_auth_hmacsha512256 5 | #define crypto_auth_verify crypto_auth_hmacsha512256_verify 6 | #define crypto_auth_BYTES crypto_auth_hmacsha512256_BYTES 7 | #define crypto_auth_KEYBYTES crypto_auth_hmacsha512256_KEYBYTES 8 | #define crypto_auth_IMPLEMENTATION crypto_auth_hmacsha512256_IMPLEMENTATION 9 | #define crypto_auth_VERSION crypto_auth_hmacsha512256_VERSION 10 | #define crypto_auth_hmacsha512256_tweet_BYTES 32 11 | #define crypto_auth_hmacsha512256_tweet_KEYBYTES 32 12 | extern int crypto_auth_hmacsha512256_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); 13 | extern int crypto_auth_hmacsha512256_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); 14 | #define crypto_auth_hmacsha512256_tweet_VERSION "-" 15 | #define crypto_auth_hmacsha512256 crypto_auth_hmacsha512256_tweet 16 | #define crypto_auth_hmacsha512256_verify crypto_auth_hmacsha512256_tweet_verify 17 | #define crypto_auth_hmacsha512256_BYTES crypto_auth_hmacsha512256_tweet_BYTES 18 | #define crypto_auth_hmacsha512256_KEYBYTES crypto_auth_hmacsha512256_tweet_KEYBYTES 19 | #define crypto_auth_hmacsha512256_VERSION crypto_auth_hmacsha512256_tweet_VERSION 20 | #define crypto_auth_hmacsha512256_IMPLEMENTATION "crypto_auth/hmacsha512256/tweet" 21 | #define crypto_box_PRIMITIVE "curve25519xsalsa20poly1305" 22 | #define crypto_box crypto_box_curve25519xsalsa20poly1305 23 | #define crypto_box_open crypto_box_curve25519xsalsa20poly1305_open 24 | #define crypto_box_keypair crypto_box_curve25519xsalsa20poly1305_keypair 25 | #define crypto_box_beforenm crypto_box_curve25519xsalsa20poly1305_beforenm 26 | #define crypto_box_afternm crypto_box_curve25519xsalsa20poly1305_afternm 27 | #define crypto_box_open_afternm crypto_box_curve25519xsalsa20poly1305_open_afternm 28 | #define crypto_box_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES 29 | #define crypto_box_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES 30 | #define crypto_box_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES 31 | #define crypto_box_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_NONCEBYTES 32 | #define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES 33 | #define crypto_box_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES 34 | #define crypto_box_IMPLEMENTATION crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION 35 | #define crypto_box_VERSION crypto_box_curve25519xsalsa20poly1305_VERSION 36 | #define crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES 32 37 | #define crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES 32 38 | #define crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES 32 39 | #define crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES 24 40 | #define crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES 32 41 | #define crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES 16 42 | extern int crypto_box_curve25519xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *); 43 | extern int crypto_box_curve25519xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *); 44 | extern int crypto_box_curve25519xsalsa20poly1305_tweet_keypair(unsigned char *,unsigned char *); 45 | extern int crypto_box_curve25519xsalsa20poly1305_tweet_beforenm(unsigned char *,const unsigned char *,const unsigned char *); 46 | extern int crypto_box_curve25519xsalsa20poly1305_tweet_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); 47 | extern int crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); 48 | #define crypto_box_curve25519xsalsa20poly1305_tweet_VERSION "-" 49 | #define crypto_box_curve25519xsalsa20poly1305 crypto_box_curve25519xsalsa20poly1305_tweet 50 | #define crypto_box_curve25519xsalsa20poly1305_open crypto_box_curve25519xsalsa20poly1305_tweet_open 51 | #define crypto_box_curve25519xsalsa20poly1305_keypair crypto_box_curve25519xsalsa20poly1305_tweet_keypair 52 | #define crypto_box_curve25519xsalsa20poly1305_beforenm crypto_box_curve25519xsalsa20poly1305_tweet_beforenm 53 | #define crypto_box_curve25519xsalsa20poly1305_afternm crypto_box_curve25519xsalsa20poly1305_tweet_afternm 54 | #define crypto_box_curve25519xsalsa20poly1305_open_afternm crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm 55 | #define crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES 56 | #define crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES 57 | #define crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES 58 | #define crypto_box_curve25519xsalsa20poly1305_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES 59 | #define crypto_box_curve25519xsalsa20poly1305_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES 60 | #define crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES 61 | #define crypto_box_curve25519xsalsa20poly1305_VERSION crypto_box_curve25519xsalsa20poly1305_tweet_VERSION 62 | #define crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION "crypto_box/curve25519xsalsa20poly1305/tweet" 63 | #define crypto_core_PRIMITIVE "salsa20" 64 | #define crypto_core crypto_core_salsa20 65 | #define crypto_core_OUTPUTBYTES crypto_core_salsa20_OUTPUTBYTES 66 | #define crypto_core_INPUTBYTES crypto_core_salsa20_INPUTBYTES 67 | #define crypto_core_KEYBYTES crypto_core_salsa20_KEYBYTES 68 | #define crypto_core_CONSTBYTES crypto_core_salsa20_CONSTBYTES 69 | #define crypto_core_IMPLEMENTATION crypto_core_salsa20_IMPLEMENTATION 70 | #define crypto_core_VERSION crypto_core_salsa20_VERSION 71 | #define crypto_core_salsa20_tweet_OUTPUTBYTES 64 72 | #define crypto_core_salsa20_tweet_INPUTBYTES 16 73 | #define crypto_core_salsa20_tweet_KEYBYTES 32 74 | #define crypto_core_salsa20_tweet_CONSTBYTES 16 75 | extern int crypto_core_salsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *); 76 | #define crypto_core_salsa20_tweet_VERSION "-" 77 | #define crypto_core_salsa20 crypto_core_salsa20_tweet 78 | #define crypto_core_salsa20_OUTPUTBYTES crypto_core_salsa20_tweet_OUTPUTBYTES 79 | #define crypto_core_salsa20_INPUTBYTES crypto_core_salsa20_tweet_INPUTBYTES 80 | #define crypto_core_salsa20_KEYBYTES crypto_core_salsa20_tweet_KEYBYTES 81 | #define crypto_core_salsa20_CONSTBYTES crypto_core_salsa20_tweet_CONSTBYTES 82 | #define crypto_core_salsa20_VERSION crypto_core_salsa20_tweet_VERSION 83 | #define crypto_core_salsa20_IMPLEMENTATION "crypto_core/salsa20/tweet" 84 | #define crypto_core_hsalsa20_tweet_OUTPUTBYTES 32 85 | #define crypto_core_hsalsa20_tweet_INPUTBYTES 16 86 | #define crypto_core_hsalsa20_tweet_KEYBYTES 32 87 | #define crypto_core_hsalsa20_tweet_CONSTBYTES 16 88 | extern int crypto_core_hsalsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *); 89 | #define crypto_core_hsalsa20_tweet_VERSION "-" 90 | #define crypto_core_hsalsa20 crypto_core_hsalsa20_tweet 91 | #define crypto_core_hsalsa20_OUTPUTBYTES crypto_core_hsalsa20_tweet_OUTPUTBYTES 92 | #define crypto_core_hsalsa20_INPUTBYTES crypto_core_hsalsa20_tweet_INPUTBYTES 93 | #define crypto_core_hsalsa20_KEYBYTES crypto_core_hsalsa20_tweet_KEYBYTES 94 | #define crypto_core_hsalsa20_CONSTBYTES crypto_core_hsalsa20_tweet_CONSTBYTES 95 | #define crypto_core_hsalsa20_VERSION crypto_core_hsalsa20_tweet_VERSION 96 | #define crypto_core_hsalsa20_IMPLEMENTATION "crypto_core/hsalsa20/tweet" 97 | #define crypto_hashblocks_PRIMITIVE "sha512" 98 | #define crypto_hashblocks crypto_hashblocks_sha512 99 | #define crypto_hashblocks_STATEBYTES crypto_hashblocks_sha512_STATEBYTES 100 | #define crypto_hashblocks_BLOCKBYTES crypto_hashblocks_sha512_BLOCKBYTES 101 | #define crypto_hashblocks_IMPLEMENTATION crypto_hashblocks_sha512_IMPLEMENTATION 102 | #define crypto_hashblocks_VERSION crypto_hashblocks_sha512_VERSION 103 | #define crypto_hashblocks_sha512_tweet_STATEBYTES 64 104 | #define crypto_hashblocks_sha512_tweet_BLOCKBYTES 128 105 | extern int crypto_hashblocks_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long); 106 | #define crypto_hashblocks_sha512_tweet_VERSION "-" 107 | #define crypto_hashblocks_sha512 crypto_hashblocks_sha512_tweet 108 | #define crypto_hashblocks_sha512_STATEBYTES crypto_hashblocks_sha512_tweet_STATEBYTES 109 | #define crypto_hashblocks_sha512_BLOCKBYTES crypto_hashblocks_sha512_tweet_BLOCKBYTES 110 | #define crypto_hashblocks_sha512_VERSION crypto_hashblocks_sha512_tweet_VERSION 111 | #define crypto_hashblocks_sha512_IMPLEMENTATION "crypto_hashblocks/sha512/tweet" 112 | #define crypto_hashblocks_sha256_tweet_STATEBYTES 32 113 | #define crypto_hashblocks_sha256_tweet_BLOCKBYTES 64 114 | extern int crypto_hashblocks_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long); 115 | #define crypto_hashblocks_sha256_tweet_VERSION "-" 116 | #define crypto_hashblocks_sha256 crypto_hashblocks_sha256_tweet 117 | #define crypto_hashblocks_sha256_STATEBYTES crypto_hashblocks_sha256_tweet_STATEBYTES 118 | #define crypto_hashblocks_sha256_BLOCKBYTES crypto_hashblocks_sha256_tweet_BLOCKBYTES 119 | #define crypto_hashblocks_sha256_VERSION crypto_hashblocks_sha256_tweet_VERSION 120 | #define crypto_hashblocks_sha256_IMPLEMENTATION "crypto_hashblocks/sha256/tweet" 121 | #define crypto_hash_PRIMITIVE "sha512" 122 | #define crypto_hash crypto_hash_sha512 123 | #define crypto_hash_BYTES crypto_hash_sha512_BYTES 124 | #define crypto_hash_IMPLEMENTATION crypto_hash_sha512_IMPLEMENTATION 125 | #define crypto_hash_VERSION crypto_hash_sha512_VERSION 126 | #define crypto_hash_sha512_tweet_BYTES 64 127 | extern int crypto_hash_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long); 128 | #define crypto_hash_sha512_tweet_VERSION "-" 129 | #define crypto_hash_sha512 crypto_hash_sha512_tweet 130 | #define crypto_hash_sha512_BYTES crypto_hash_sha512_tweet_BYTES 131 | #define crypto_hash_sha512_VERSION crypto_hash_sha512_tweet_VERSION 132 | #define crypto_hash_sha512_IMPLEMENTATION "crypto_hash/sha512/tweet" 133 | #define crypto_hash_sha256_tweet_BYTES 32 134 | extern int crypto_hash_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long); 135 | #define crypto_hash_sha256_tweet_VERSION "-" 136 | #define crypto_hash_sha256 crypto_hash_sha256_tweet 137 | #define crypto_hash_sha256_BYTES crypto_hash_sha256_tweet_BYTES 138 | #define crypto_hash_sha256_VERSION crypto_hash_sha256_tweet_VERSION 139 | #define crypto_hash_sha256_IMPLEMENTATION "crypto_hash/sha256/tweet" 140 | #define crypto_onetimeauth_PRIMITIVE "poly1305" 141 | #define crypto_onetimeauth crypto_onetimeauth_poly1305 142 | #define crypto_onetimeauth_verify crypto_onetimeauth_poly1305_verify 143 | #define crypto_onetimeauth_BYTES crypto_onetimeauth_poly1305_BYTES 144 | #define crypto_onetimeauth_KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES 145 | #define crypto_onetimeauth_IMPLEMENTATION crypto_onetimeauth_poly1305_IMPLEMENTATION 146 | #define crypto_onetimeauth_VERSION crypto_onetimeauth_poly1305_VERSION 147 | #define crypto_onetimeauth_poly1305_tweet_BYTES 16 148 | #define crypto_onetimeauth_poly1305_tweet_KEYBYTES 32 149 | extern int crypto_onetimeauth_poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); 150 | extern int crypto_onetimeauth_poly1305_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); 151 | #define crypto_onetimeauth_poly1305_tweet_VERSION "-" 152 | #define crypto_onetimeauth_poly1305 crypto_onetimeauth_poly1305_tweet 153 | #define crypto_onetimeauth_poly1305_verify crypto_onetimeauth_poly1305_tweet_verify 154 | #define crypto_onetimeauth_poly1305_BYTES crypto_onetimeauth_poly1305_tweet_BYTES 155 | #define crypto_onetimeauth_poly1305_KEYBYTES crypto_onetimeauth_poly1305_tweet_KEYBYTES 156 | #define crypto_onetimeauth_poly1305_VERSION crypto_onetimeauth_poly1305_tweet_VERSION 157 | #define crypto_onetimeauth_poly1305_IMPLEMENTATION "crypto_onetimeauth/poly1305/tweet" 158 | #define crypto_scalarmult_PRIMITIVE "curve25519" 159 | #define crypto_scalarmult crypto_scalarmult_curve25519 160 | #define crypto_scalarmult_base crypto_scalarmult_curve25519_base 161 | #define crypto_scalarmult_BYTES crypto_scalarmult_curve25519_BYTES 162 | #define crypto_scalarmult_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES 163 | #define crypto_scalarmult_IMPLEMENTATION crypto_scalarmult_curve25519_IMPLEMENTATION 164 | #define crypto_scalarmult_VERSION crypto_scalarmult_curve25519_VERSION 165 | #define crypto_scalarmult_curve25519_tweet_BYTES 32 166 | #define crypto_scalarmult_curve25519_tweet_SCALARBYTES 32 167 | extern int crypto_scalarmult_curve25519_tweet(unsigned char *,const unsigned char *,const unsigned char *); 168 | extern int crypto_scalarmult_curve25519_tweet_base(unsigned char *,const unsigned char *); 169 | #define crypto_scalarmult_curve25519_tweet_VERSION "-" 170 | #define crypto_scalarmult_curve25519 crypto_scalarmult_curve25519_tweet 171 | #define crypto_scalarmult_curve25519_base crypto_scalarmult_curve25519_tweet_base 172 | #define crypto_scalarmult_curve25519_BYTES crypto_scalarmult_curve25519_tweet_BYTES 173 | #define crypto_scalarmult_curve25519_SCALARBYTES crypto_scalarmult_curve25519_tweet_SCALARBYTES 174 | #define crypto_scalarmult_curve25519_VERSION crypto_scalarmult_curve25519_tweet_VERSION 175 | #define crypto_scalarmult_curve25519_IMPLEMENTATION "crypto_scalarmult/curve25519/tweet" 176 | #define crypto_secretbox_PRIMITIVE "xsalsa20poly1305" 177 | #define crypto_secretbox crypto_secretbox_xsalsa20poly1305 178 | #define crypto_secretbox_open crypto_secretbox_xsalsa20poly1305_open 179 | #define crypto_secretbox_KEYBYTES crypto_secretbox_xsalsa20poly1305_KEYBYTES 180 | #define crypto_secretbox_NONCEBYTES crypto_secretbox_xsalsa20poly1305_NONCEBYTES 181 | #define crypto_secretbox_ZEROBYTES crypto_secretbox_xsalsa20poly1305_ZEROBYTES 182 | #define crypto_secretbox_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES 183 | #define crypto_secretbox_IMPLEMENTATION crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION 184 | #define crypto_secretbox_VERSION crypto_secretbox_xsalsa20poly1305_VERSION 185 | #define crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES 32 186 | #define crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES 24 187 | #define crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES 32 188 | #define crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES 16 189 | extern int crypto_secretbox_xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); 190 | extern int crypto_secretbox_xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); 191 | #define crypto_secretbox_xsalsa20poly1305_tweet_VERSION "-" 192 | #define crypto_secretbox_xsalsa20poly1305 crypto_secretbox_xsalsa20poly1305_tweet 193 | #define crypto_secretbox_xsalsa20poly1305_open crypto_secretbox_xsalsa20poly1305_tweet_open 194 | #define crypto_secretbox_xsalsa20poly1305_KEYBYTES crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES 195 | #define crypto_secretbox_xsalsa20poly1305_NONCEBYTES crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES 196 | #define crypto_secretbox_xsalsa20poly1305_ZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES 197 | #define crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES 198 | #define crypto_secretbox_xsalsa20poly1305_VERSION crypto_secretbox_xsalsa20poly1305_tweet_VERSION 199 | #define crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION "crypto_secretbox/xsalsa20poly1305/tweet" 200 | #define crypto_sign_PRIMITIVE "ed25519" 201 | #define crypto_sign crypto_sign_ed25519 202 | #define crypto_sign_open crypto_sign_ed25519_open 203 | #define crypto_sign_keypair crypto_sign_ed25519_keypair 204 | #define crypto_sign_BYTES crypto_sign_ed25519_BYTES 205 | #define crypto_sign_PUBLICKEYBYTES crypto_sign_ed25519_PUBLICKEYBYTES 206 | #define crypto_sign_SECRETKEYBYTES crypto_sign_ed25519_SECRETKEYBYTES 207 | #define crypto_sign_IMPLEMENTATION crypto_sign_ed25519_IMPLEMENTATION 208 | #define crypto_sign_VERSION crypto_sign_ed25519_VERSION 209 | #define crypto_sign_ed25519_tweet_BYTES 64 210 | #define crypto_sign_ed25519_tweet_PUBLICKEYBYTES 32 211 | #define crypto_sign_ed25519_tweet_SECRETKEYBYTES 64 212 | extern int crypto_sign_ed25519_tweet(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); 213 | extern int crypto_sign_ed25519_tweet_open(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); 214 | extern int crypto_sign_ed25519_tweet_keypair(unsigned char *,unsigned char *); 215 | #define crypto_sign_ed25519_tweet_VERSION "-" 216 | #define crypto_sign_ed25519 crypto_sign_ed25519_tweet 217 | #define crypto_sign_ed25519_open crypto_sign_ed25519_tweet_open 218 | #define crypto_sign_ed25519_keypair crypto_sign_ed25519_tweet_keypair 219 | #define crypto_sign_ed25519_BYTES crypto_sign_ed25519_tweet_BYTES 220 | #define crypto_sign_ed25519_PUBLICKEYBYTES crypto_sign_ed25519_tweet_PUBLICKEYBYTES 221 | #define crypto_sign_ed25519_SECRETKEYBYTES crypto_sign_ed25519_tweet_SECRETKEYBYTES 222 | #define crypto_sign_ed25519_VERSION crypto_sign_ed25519_tweet_VERSION 223 | #define crypto_sign_ed25519_IMPLEMENTATION "crypto_sign/ed25519/tweet" 224 | #define crypto_stream_PRIMITIVE "xsalsa20" 225 | #define crypto_stream crypto_stream_xsalsa20 226 | #define crypto_stream_xor crypto_stream_xsalsa20_xor 227 | #define crypto_stream_KEYBYTES crypto_stream_xsalsa20_KEYBYTES 228 | #define crypto_stream_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES 229 | #define crypto_stream_IMPLEMENTATION crypto_stream_xsalsa20_IMPLEMENTATION 230 | #define crypto_stream_VERSION crypto_stream_xsalsa20_VERSION 231 | #define crypto_stream_xsalsa20_tweet_KEYBYTES 32 232 | #define crypto_stream_xsalsa20_tweet_NONCEBYTES 24 233 | extern int crypto_stream_xsalsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); 234 | extern int crypto_stream_xsalsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); 235 | #define crypto_stream_xsalsa20_tweet_VERSION "-" 236 | #define crypto_stream_xsalsa20 crypto_stream_xsalsa20_tweet 237 | #define crypto_stream_xsalsa20_xor crypto_stream_xsalsa20_tweet_xor 238 | #define crypto_stream_xsalsa20_KEYBYTES crypto_stream_xsalsa20_tweet_KEYBYTES 239 | #define crypto_stream_xsalsa20_NONCEBYTES crypto_stream_xsalsa20_tweet_NONCEBYTES 240 | #define crypto_stream_xsalsa20_VERSION crypto_stream_xsalsa20_tweet_VERSION 241 | #define crypto_stream_xsalsa20_IMPLEMENTATION "crypto_stream/xsalsa20/tweet" 242 | #define crypto_stream_salsa20_tweet_KEYBYTES 32 243 | #define crypto_stream_salsa20_tweet_NONCEBYTES 8 244 | extern int crypto_stream_salsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); 245 | extern int crypto_stream_salsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); 246 | #define crypto_stream_salsa20_tweet_VERSION "-" 247 | #define crypto_stream_salsa20 crypto_stream_salsa20_tweet 248 | #define crypto_stream_salsa20_xor crypto_stream_salsa20_tweet_xor 249 | #define crypto_stream_salsa20_KEYBYTES crypto_stream_salsa20_tweet_KEYBYTES 250 | #define crypto_stream_salsa20_NONCEBYTES crypto_stream_salsa20_tweet_NONCEBYTES 251 | #define crypto_stream_salsa20_VERSION crypto_stream_salsa20_tweet_VERSION 252 | #define crypto_stream_salsa20_IMPLEMENTATION "crypto_stream/salsa20/tweet" 253 | #define crypto_verify_PRIMITIVE "16" 254 | #define crypto_verify crypto_verify_16 255 | #define crypto_verify_BYTES crypto_verify_16_BYTES 256 | #define crypto_verify_IMPLEMENTATION crypto_verify_16_IMPLEMENTATION 257 | #define crypto_verify_VERSION crypto_verify_16_VERSION 258 | #define crypto_verify_16_tweet_BYTES 16 259 | extern int crypto_verify_16_tweet(const unsigned char *,const unsigned char *); 260 | #define crypto_verify_16_tweet_VERSION "-" 261 | #define crypto_verify_16 crypto_verify_16_tweet 262 | #define crypto_verify_16_BYTES crypto_verify_16_tweet_BYTES 263 | #define crypto_verify_16_VERSION crypto_verify_16_tweet_VERSION 264 | #define crypto_verify_16_IMPLEMENTATION "crypto_verify/16/tweet" 265 | #define crypto_verify_32_tweet_BYTES 32 266 | extern int crypto_verify_32_tweet(const unsigned char *,const unsigned char *); 267 | #define crypto_verify_32_tweet_VERSION "-" 268 | #define crypto_verify_32 crypto_verify_32_tweet 269 | #define crypto_verify_32_BYTES crypto_verify_32_tweet_BYTES 270 | #define crypto_verify_32_VERSION crypto_verify_32_tweet_VERSION 271 | #define crypto_verify_32_IMPLEMENTATION "crypto_verify/32/tweet" 272 | #endif 273 | -------------------------------------------------------------------------------- /openssl/spin: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | VERSION=$1 3 | if [[ -z $VERSION ]]; then 4 | echo "USAGE: $0 0.9.xy" 5 | exit 1 6 | fi 7 | 8 | mkdir -p $HOME/ssl/build 9 | cd $HOME/ssl/build 10 | 11 | set -ex 12 | [ -f openssl-$VERSION.tar.gz ] || wget ftp://ftp.openssl.org/source/old/0.9.x/openssl-$VERSION.tar.gz 13 | tar -xzvf openssl-$VERSION.tar.gz 14 | cd openssl-$VERSION 15 | 16 | egrep -ril '^=item [0-9]+$' doc/ | xargs sed -i -e 's/=item \(.*\)/=item C<\1>/' 17 | ./config --prefix=$HOME/ssl/$VERSION --shared 18 | make 19 | make test 20 | make install 21 | find . -name '*.so' 22 | -------------------------------------------------------------------------------- /rcu/.gitignore: -------------------------------------------------------------------------------- 1 | /run-* 2 | /*.data 3 | /trial.png 4 | /tmp 5 | -------------------------------------------------------------------------------- /rcu/Makefile: -------------------------------------------------------------------------------- 1 | all: run-lock run-qs 2 | clean: 3 | rm -f run-* 4 | rm -f */*.o 5 | 6 | run-lock: lock/main.o 7 | $(CC) -o $@ -I. $+ 8 | 9 | run-qs: qs/main.o 10 | $(CC) -o $@ -I. $+ 11 | 12 | data: trial.png 13 | trial.png: out.data 14 | ./plot > $@ 15 | [[ -z "$$(command -v open)" ]] || open $@ 16 | out.data: run-lock run-qs report 17 | ./report > out.data 18 | -------------------------------------------------------------------------------- /rcu/api.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static inline void 4 | spin_up(void *(*fn)(void *), void *restrict arg) 5 | { 6 | pthread_t tid; 7 | if (pthread_create(&tid, NULL, fn, arg) != 0) { 8 | perror("pthread_create"); 9 | exit(3); 10 | } 11 | } 12 | 13 | static inline void 14 | make_lock(pthread_mutex_t *lck) 15 | { 16 | if (pthread_mutex_init(lck, NULL) != 0) { 17 | perror("pthread_mutex_init"); 18 | exit(3); 19 | } 20 | } 21 | 22 | static inline void 23 | lock(pthread_mutex_t *lck) { 24 | if (pthread_mutex_lock(lck) != 0) { \ 25 | perror("pthread_mutex_lock"); \ 26 | exit(3); \ 27 | } \ 28 | } 29 | 30 | static inline void 31 | unlock(pthread_mutex_t *lck) { 32 | if (pthread_mutex_unlock(lck) != 0) { 33 | perror("pthread_mutex_unlock"); 34 | exit(3); 35 | } 36 | } 37 | 38 | #define xmalloc(n) xcalloc(1,(n)) 39 | static inline void* 40 | xcalloc(size_t n, size_t len) 41 | { 42 | void *p = calloc(n, len); 43 | if (!p) { 44 | perror("calloc"); 45 | exit(3); 46 | } 47 | return p; 48 | } 49 | -------------------------------------------------------------------------------- /rcu/lock/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../api.h" 6 | 7 | /* 8 | 9 | rcu/lock 10 | 11 | This is a naïve implementation of concurrent data sharing 12 | across multiple threads that utilized mutex locks to ensure 13 | that threads see a consistent set of data. 14 | 15 | If my understanding of RCU read-side primitive overhead is 16 | correct, this program should execute the slowest, given the 17 | same starting parameters (number of threads, write cycles, 18 | and reads per write cycle). 19 | 20 | */ 21 | 22 | 23 | static unsigned char 24 | hashit(const char *s) 25 | { 26 | unsigned int h = 81; 27 | unsigned char c; 28 | 29 | while ((c = *s++)) 30 | h = ((h << 5) + h) + c; 31 | 32 | return h & ~0xc0; 33 | } 34 | 35 | struct hlist { 36 | struct hlist *next; 37 | char *key; 38 | void *value; 39 | }; 40 | typedef struct { 41 | struct hlist h[64]; 42 | } hash_t; 43 | 44 | static void* 45 | hash_get(hash_t *h, const char *k) 46 | { 47 | struct hlist *hl; 48 | for (hl = h->hlist[hashit(k)]; hl, hl = hl->next) { 49 | if (strcmp(hl->key, k) == 0) { 50 | return hl->value; 51 | } 52 | } 53 | return NULL; 54 | } 55 | 56 | static void 57 | hash_set(hash_t *h, const char *k, void *v) 58 | { 59 | return; 60 | } 61 | 62 | pthread_mutex_t LOCK; 63 | unsigned long long *COUNTER; 64 | 65 | void writer(int cycles) 66 | { 67 | while (cycles--) { 68 | lock(&LOCK); 69 | *COUNTER += 1; 70 | fprintf(stderr, "[writer] incremented COUNTER to %llu\n", *COUNTER); 71 | unlock(&LOCK); 72 | } 73 | } 74 | 75 | void* reader(void *_) 76 | { 77 | int id = *(int *)_; 78 | 79 | for (;;) { 80 | lock(&LOCK); 81 | fprintf(stderr, "[t%d] read COUNTER at %llu\n", id, *COUNTER); 82 | unlock(&LOCK); 83 | } 84 | 85 | return _; 86 | } 87 | 88 | int main(int argc, char **argv) 89 | { 90 | struct timeval start, end; 91 | pthread_t tid; 92 | int rc, i, nthreads, cycles, *ids; 93 | void *status; 94 | 95 | if (argc != 3) { 96 | fprintf(stderr, "USAGE: %s THREADS CYCLES READS\n", argv[0]); 97 | exit(2); 98 | } 99 | 100 | nthreads = atoi(argv[1]); 101 | cycles = atoi(argv[2]); 102 | if (nthreads < 1) { 103 | fprintf(stderr, "Invalid THREADS value %s (must be > 0)\n", argv[1]); 104 | fprintf(stderr, "USAGE: %s THREADS CYCLES READS\n", argv[0]); 105 | exit(2); 106 | } 107 | if (cycles < 1) { 108 | fprintf(stderr, "Invalid WRITE_CYCLES value %s (must be > 0)\n", argv[2]); 109 | fprintf(stderr, "USAGE: %s THREADS CYCLES READS\n", argv[0]); 110 | exit(2); 111 | } 112 | 113 | make_lock(&LOCK); 114 | ids = xcalloc(nthreads, sizeof(int)); 115 | COUNTER = xmalloc(sizeof(unsigned long long)); 116 | 117 | for (i = 0; i < nthreads; i++) { 118 | pthread_t tid; 119 | ids[i] = i+1; 120 | 121 | rc = pthread_create(&tid, NULL, reader, &ids[i]); 122 | if (rc != 0) { 123 | perror("pthread_create"); 124 | exit(3); 125 | } 126 | } 127 | 128 | gettimeofday(&start, NULL); 129 | writer(cycles); 130 | gettimeofday(&end, NULL); 131 | 132 | if (end.tv_usec < start.tv_usec) { 133 | end.tv_sec--; 134 | end.tv_usec += 1000000; 135 | } 136 | 137 | fprintf(stdout, "%i %li\n", nthreads, 138 | ((end.tv_sec - start.tv_sec) * 1000000) + (end.tv_usec - start.tv_usec)); 139 | 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /rcu/plot: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env gnuplot 2 | 3 | set terminal png 4 | datafile = 'out.data' 5 | 6 | plot datafile using 1:2 with lines, \ 7 | datafile using 1:3 with lines 8 | -------------------------------------------------------------------------------- /rcu/qs/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "../api.h" 7 | 8 | /* 9 | 10 | rcu/qs 11 | 12 | This is the _Quiescent State_ implementation of RCU for 13 | concurrent data sharing across multiple threads. Under 14 | QS, the threads are responsible for identifying their 15 | quiescent states (when they are no longer able to update 16 | the old copy of shared data). 17 | 18 | I could very well have gotten the implementation horribly 19 | wrong. Please bear with me here... 20 | 21 | */ 22 | 23 | /* NUM_THREADS puts a fixed limit on the number of threads 24 | that can be spun up, such that we can use static arrays 25 | to imitate "weak" thread-local storage. 26 | 27 | This is one of many concessions that an application 28 | wishing to take advantage of quiescent state-based RCU 29 | needs to make, and why QSBR may not be universally 30 | applicable (i.e. via a library) */ 31 | #define NUM_THREADS 128 32 | 33 | /* NO_THREAD is a _sigil value_ that identifies if a slot 34 | in a per-thread variable is available (set to NO_THREAD) 35 | or occupied (set to anything else). */ 36 | #define NO_THREAD ((pthread_t)(0UL)) 37 | 38 | /* Define a per-thread variable, for the calling thread. 39 | 40 | We imitate a weaker form of true thread-local storage by 41 | using an array of things, with enough elements 42 | to store a distinct value for up to NUM_THREADS. 43 | 44 | The "weak" adjective refers to the ability for other 45 | threads to peer into the variable scope of other threads, 46 | which is impossible with POSIX pthreads thead-local 47 | implementations. */ 48 | #define DEFINE_PER_THREAD(type,name) static type __per_thread_ ## name[NUM_THREADS] 49 | #define for_each_thread(t) for (t = 0; t < NUM_THREADS; t++) 50 | 51 | pthread_mutex_t tid_lock; 52 | DEFINE_PER_THREAD(pthread_t, tid) = {0}; 53 | 54 | /* Retrieve a per-thread variable, for the calling thread. */ 55 | #define MY(var) THEIR(_thread_index(pthread_self()), var) 56 | 57 | /* Retrieve a per-thread variable, for some other thread. */ 58 | #define THEIR(idx,var) __per_thread_##var[idx] 59 | 60 | static inline 61 | int _thread_index(pthread_t tid) 62 | { 63 | int t; 64 | for_each_thread(t) { 65 | if (__per_thread_tid[t] == tid) { 66 | return t; 67 | } 68 | } 69 | fprintf(stderr, "unrecognized thread %p\n", tid); 70 | exit(1); 71 | } 72 | 73 | static inline 74 | void register_thread() 75 | { 76 | int t; 77 | 78 | lock(&tid_lock); 79 | for_each_thread(t) { 80 | if (__per_thread_tid[t] == NO_THREAD) { 81 | __per_thread_tid[t] = pthread_self(); 82 | unlock(&tid_lock); 83 | return; 84 | } 85 | } 86 | fprintf(stderr, "self-destruct: unable to register %p - out of thread slots\n", pthread_self()); 87 | exit(1); 88 | } 89 | 90 | static inline 91 | void deregister_thread() 92 | { 93 | MY(tid) = NO_THREAD; 94 | } 95 | 96 | /* Prevent compiler optimizations for memory access */ 97 | /* (use of `volatile' keyword stops most sane compilers 98 | from duplicating de-duplicating variable / register access) */ 99 | #define ONCE(x) (*(volatile typeof(x) *)&(x)) 100 | 101 | /* Prevent compiler optimizations for memory reordering 102 | (this is a compile-time barrier to ensure that the optimizer 103 | doesn't try to "improve" how we access memory, and thereby 104 | ruin our carefully crafted concurrent code) */ 105 | #define barrier() asm volatile("" ::: "memory") 106 | 107 | pthread_mutex_t rcu_gp_lock; 108 | long rcu_gp_ctr = 0; 109 | DEFINE_PER_THREAD(long, rcu_reader_qs_gp); 110 | 111 | static inline void rcu_read_lock(void) 112 | { 113 | } 114 | 115 | static inline void rcu_read_unlock(void) 116 | { 117 | } 118 | 119 | static inline void rcu_quiescent_state(void) 120 | { 121 | barrier(); 122 | MY(rcu_reader_qs_gp) = ONCE(rcu_gp_ctr) + 1; 123 | barrier(); 124 | } 125 | 126 | static inline void rcu_thread_offline(void) 127 | { 128 | barrier(); 129 | MY(rcu_reader_qs_gp) = ONCE(rcu_gp_ctr); 130 | } 131 | static inline void rcu_thread_online(void) 132 | { 133 | MY(rcu_reader_qs_gp) = ONCE(rcu_gp_ctr) + 1; 134 | barrier(); 135 | } 136 | 137 | static inline int rcu_gp_ongoing(int idx) 138 | { 139 | return THEIR(idx, rcu_reader_qs_gp) & 1; 140 | } 141 | 142 | void synchronize_rcu(void) 143 | { 144 | int t; 145 | 146 | barrier(); 147 | lock(&rcu_gp_lock); 148 | rcu_gp_ctr += 2; 149 | for_each_thread(t) { 150 | while (rcu_gp_ongoing(t) && 151 | ((THEIR(t, rcu_reader_qs_gp) - rcu_gp_ctr) < 0)) { 152 | poll(NULL, 0, 10); 153 | barrier(); 154 | } 155 | } 156 | unlock(&rcu_gp_lock); 157 | barrier(); 158 | } 159 | 160 | /***********************************************************/ 161 | 162 | pthread_mutex_t LOCK; 163 | unsigned long long *COUNTER; 164 | 165 | static inline 166 | void writer(int cycles) 167 | { 168 | unsigned long long *OLD, *NEW; 169 | 170 | while (cycles--) { 171 | 172 | NEW = xmalloc(sizeof(*NEW)); 173 | 174 | lock(&LOCK); 175 | OLD = COUNTER; 176 | *NEW = *OLD + 1; 177 | COUNTER = NEW; 178 | unlock(&LOCK); 179 | 180 | fprintf(stderr, "[writer] incremented COUNTER to %llu\n", *NEW); 181 | 182 | synchronize_rcu(); 183 | free(OLD); 184 | } 185 | } 186 | 187 | static inline 188 | void sleep_ms(int ms) 189 | { 190 | struct timespec tv; 191 | tv.tv_sec = 0; 192 | tv.tv_nsec = ms * 1000000; 193 | nanosleep(&tv, NULL); 194 | } 195 | 196 | void* reader(void *_) 197 | { 198 | int id = *(int *)_; 199 | 200 | register_thread(); 201 | 202 | for (;;) { 203 | rcu_read_lock(); 204 | fprintf(stderr, "[t%d] read COUNTER at %llu\n", id, *(ONCE(COUNTER))); 205 | // sleep_ms(10); 206 | rcu_read_unlock(); 207 | rcu_quiescent_state(); 208 | } 209 | 210 | return _; 211 | } 212 | 213 | static void rcu_init() 214 | { 215 | int rc; 216 | 217 | make_lock(&rcu_gp_lock); 218 | make_lock(&tid_lock); 219 | } 220 | 221 | int main(int argc, char **argv) 222 | { 223 | struct timeval start, end; 224 | pthread_t tid; 225 | int rc, i, nthreads, cycles, *ids; 226 | void *status; 227 | 228 | if (argc != 3) { 229 | fprintf(stderr, "USAGE: %s THREADS CYCLES\n", argv[0]); 230 | exit(2); 231 | } 232 | 233 | nthreads = atoi(argv[1]); 234 | cycles = atoi(argv[2]); 235 | if (nthreads < 1) { 236 | fprintf(stderr, "Invalid THREADS value %s (must be > 0)\n", argv[1]); 237 | fprintf(stderr, "USAGE: %s THREADS CYCLES\n", argv[0]); 238 | exit(2); 239 | } 240 | if (cycles < 1) { 241 | fprintf(stderr, "Invalid WRITE_CYCLES value %s (must be > 0)\n", argv[2]); 242 | fprintf(stderr, "USAGE: %s THREADS CYCLES\n", argv[0]); 243 | exit(2); 244 | } 245 | 246 | rcu_init(); 247 | 248 | make_lock(&LOCK); 249 | ids = xcalloc(nthreads, sizeof(int)); 250 | COUNTER = xcalloc(1, sizeof(unsigned long long)); 251 | 252 | for (i = 0; i < nthreads; i++) { 253 | ids[i] = i+1; 254 | spin_up(reader, &ids[i]); 255 | } 256 | 257 | //sleep_ms(9); 258 | gettimeofday(&start, NULL); 259 | writer(cycles); 260 | gettimeofday(&end, NULL); 261 | 262 | if (end.tv_usec < start.tv_usec) { 263 | end.tv_sec--; 264 | end.tv_usec += 1000000; 265 | } 266 | 267 | fprintf(stdout, "%i %li\n", nthreads, 268 | ((end.tv_sec - start.tv_sec) * 1000000) + (end.tv_usec - start.tv_usec)); 269 | 270 | return 0; 271 | } 272 | -------------------------------------------------------------------------------- /rcu/report: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | rm -fr tmp/ && mkdir -p tmp/ 5 | for x in 1 2 4 8 12 16 20 24 32 40 48 64 96 128; do ./run-lock $x 10000 2>/dev/null >> tmp/lock.data; done 6 | for x in 1 2 4 8 12 16 20 24 32 40 48 64 96 128; do ./run-qs $x 10000 2>/dev/null >> tmp/qs.data; done 7 | join tmp/lock.data tmp/qs.data 8 | rm -fr tmp/ 9 | -------------------------------------------------------------------------------- /regm/.gitignore: -------------------------------------------------------------------------------- 1 | regm 2 | asm 3 | *.o 4 | *.b 5 | *.s 6 | -------------------------------------------------------------------------------- /regm/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := -g -Wall 2 | LDLIBS := -lvigor 3 | 4 | BINARIES := 5 | BINARIES += regm 6 | BINARIES += asm 7 | 8 | EXAMPLES_SRC := $(shell ls -1 pn/*.pn) 9 | EXAMPLES_BIN := $(shell ls -1 pn/*.pn | sed -e 's/\.pn/.b/') 10 | 11 | ################################################ 12 | # DUMMY TARGETS 13 | 14 | default: $(BINARIES) 15 | clean: 16 | rm -f *.o asm regm 17 | rm -f $(EXAMPLES_BIN) 18 | 19 | test: default 20 | ./regm 21 | 22 | examples: $(EXAMPLES_BIN) 23 | 24 | 25 | ################################################ 26 | # BINARY targets 27 | 28 | regm: regm.o 29 | asm: asm.o 30 | 31 | ################################################ 32 | # SUPPORTING targets 33 | 34 | opcodes.h: opcodes.yml gencode 35 | ./gencode opcodes > $@ 36 | 37 | pn/%.b: pn/%.pn asm 38 | ./asm <$< >$@ 39 | -------------------------------------------------------------------------------- /regm/README.md: -------------------------------------------------------------------------------- 1 | regm - jameshunt(.us) Research 2 | ============================== 3 | 4 | Research into register machine design and implementation, for PN.2, the 5 | second iteration of the [Clockwork][clockwork] Pendulum Virtual Machine. 6 | 7 | [clockwork]: https://github.com/filefrog/clockwork 8 | -------------------------------------------------------------------------------- /regm/asm.c: -------------------------------------------------------------------------------- 1 | #define _POSIX_C_SOURCE 200809L 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "regm.h" 8 | 9 | #define OPCODES_EXTENDED 10 | #include "opcodes.h" 11 | 12 | static const char * VTYPES[] = { 13 | "NONE", 14 | "register", 15 | "number", 16 | "string", 17 | "address", 18 | "label", 19 | "offset", 20 | "fnlabel", 21 | NULL, 22 | }; 23 | 24 | #define VALUE_NONE 0x0 25 | #define VALUE_REGISTER 0x1 26 | #define VALUE_NUMBER 0x2 27 | #define VALUE_STRING 0x3 28 | #define VALUE_ADDRESS 0x4 29 | #define VALUE_LABEL 0x5 30 | #define VALUE_FNLABEL 0x6 31 | #define VALUE_OFFSET 0x7 32 | 33 | #define TYPE_LITERAL 0x1 34 | #define TYPE_REGISTER 0x2 35 | #define TYPE_ADDRESS 0x3 36 | 37 | typedef struct { 38 | byte_t type; 39 | byte_t bintype; 40 | union { 41 | char regname; /* register (a, c, etc.) */ 42 | dword_t literal; /* literal value */ 43 | char *string; /* string value */ 44 | dword_t address; /* memory address */ 45 | char *label; /* for labelled jumps */ 46 | char *fnlabel; /* for labelled jumps */ 47 | dword_t offset; /* for relative jumps */ 48 | } _; 49 | } value_t; 50 | 51 | #define SPECIAL_LABEL 1 52 | #define SPECIAL_FUNC 2 53 | typedef struct { 54 | byte_t special; /* identify special, non-code markers */ 55 | char *label; /* special label */ 56 | void *fn; /* link to the FN that starts scope */ 57 | 58 | byte_t op; /* opcode number, for final encoding */ 59 | value_t args[2]; /* operands */ 60 | 61 | dword_t offset; /* byte offset in opcode binary stream */ 62 | list_t l; 63 | } op_t; 64 | 65 | typedef struct { 66 | const char *name; /* name of the flag (for source correlation) */ 67 | dword_t idx; /* index into heap array (address) */ 68 | list_t l; 69 | } flag_t; 70 | 71 | typedef struct { 72 | byte_t *mem; 73 | size_t total; 74 | size_t used; 75 | size_t burst; 76 | dword_t offset; 77 | } static_t; 78 | 79 | list_t OPS; 80 | static_t STATIC; 81 | byte_t *CODE; 82 | 83 | 84 | #define LINE_BUF_SIZE 8192 85 | typedef struct { 86 | FILE *io; 87 | const char *file; 88 | int line; 89 | int token; 90 | char value[LINE_BUF_SIZE]; 91 | char buffer[LINE_BUF_SIZE]; 92 | char raw[LINE_BUF_SIZE]; 93 | } parser_t; 94 | 95 | #define T_REGISTER 0x01 96 | #define T_LABEL 0x02 97 | #define T_IDENTIFIER 0x03 98 | #define T_OFFSET 0x04 99 | #define T_NUMBER 0x05 100 | #define T_STRING 0x06 101 | #define T_OPCODE 0x07 102 | #define T_FUNCTION 0x08 103 | #define T_TOPIC 0x09 104 | 105 | static const char * T_names[] = { 106 | "(NONE)", 107 | "T_REGISTER", 108 | "T_LABEL", 109 | "T_IDENTIFIER", 110 | "T_OFFSET", 111 | "T_NUMBER", 112 | "T_STRING", 113 | "T_OPCODE", 114 | "T_FUNCTION", 115 | "T_TOPIC", 116 | NULL, 117 | }; 118 | 119 | static int lex(parser_t *p) 120 | { 121 | char *a, *b; 122 | if (!*p->buffer || *p->buffer == ';') { 123 | getline: 124 | if (!fgets(p->raw, LINE_BUF_SIZE, p->io)) 125 | return 0; 126 | p->line++; 127 | 128 | a = p->raw; 129 | while (*a && isspace(*a)) a++; 130 | if (*a == ';') 131 | while (*a && *a != '\n') a++; 132 | while (*a && isspace(*a)) a++; 133 | if (!*a) 134 | goto getline; 135 | 136 | b = p->buffer; 137 | while ((*b++ = *a++)); 138 | } 139 | p->token = 0; 140 | p->value[0] = '\0'; 141 | 142 | b = p->buffer; 143 | while (*b && isspace(*b)) b++; 144 | a = b; 145 | 146 | if (*b == '%') { /* register */ 147 | while (!isspace(*b)) b++; 148 | if (!*b || isspace(*b)) { 149 | *b = '\0'; 150 | char reg = 0; 151 | if (b - a == 2) 152 | reg = *(a + 1); 153 | if (reg < 'a' || reg >= 'a'+NREGS) { 154 | logger(LOG_ERR, "%s:%i: unrecognized register address %s (%i)", p->file, p->line, a, reg); 155 | return 0; 156 | } 157 | 158 | p->token = T_REGISTER; 159 | p->value[0] = reg; 160 | p->value[1] = '\0'; 161 | 162 | b++; while (*b && isspace(*b)) b++; 163 | memmove(p->buffer, b, strlen(b)+1); 164 | return 1; 165 | } 166 | b = a; 167 | } 168 | 169 | if (*b == '+' || *b == '-') { 170 | b++; 171 | while (*b && isdigit(*b)) b++; 172 | if (!*b || isspace(*b)) { 173 | *b++ = '\0'; 174 | 175 | p->token = T_OFFSET; 176 | memcpy(p->value, p->buffer, b-p->buffer); 177 | 178 | while (*b && isspace(*b)) b++; 179 | memmove(p->buffer, b, strlen(b)+1); 180 | return 1; 181 | } 182 | b = a; 183 | } 184 | 185 | if (isdigit(*b)) { 186 | if (*b == '0' && *(b+1) == 'x') { 187 | b += 2; 188 | while (*b && isxdigit(*b)) b++; 189 | } else { 190 | while (*b && isdigit(*b)) b++; 191 | } 192 | if (!*b || isspace(*b)) { 193 | *b++ = '\0'; 194 | 195 | p->token = T_NUMBER; 196 | memcpy(p->value, p->buffer, b-p->buffer); 197 | 198 | while (*b && isspace(*b)) b++; 199 | memmove(p->buffer, b, strlen(b)+1); 200 | return 1; 201 | } 202 | b = a; 203 | } 204 | 205 | if (isalpha(*b)) { 206 | while (*b && !isspace(*b) && *b != ':') 207 | b++; 208 | if (*b == ':') { 209 | *b++ = '\0'; 210 | p->token = T_LABEL; 211 | memcpy(p->value, p->buffer, b-p->buffer); 212 | while (*b && isspace(*b)) b++; 213 | memmove(p->buffer, b, strlen(b)+1); 214 | return 1; 215 | } 216 | b = a; 217 | 218 | while (*b && (isalnum(*b) || *b == '.' || *b == '_' || *b == '?')) 219 | b++; 220 | *b++ = '\0'; 221 | 222 | int i; 223 | for (i = 0; ASM[i]; i++) { 224 | if (strcmp(a, ASM[i]) != 0) continue; 225 | p->token = T_OPCODE; 226 | p->value[0] = T_OPCODE_NOOP + i; 227 | p->value[1] = '\0'; 228 | break; 229 | } 230 | 231 | if (strcmp(a, "fn") == 0) p->token = T_FUNCTION; 232 | 233 | if (!p->token) { 234 | p->token = T_IDENTIFIER; 235 | memcpy(p->value, p->buffer, b-p->buffer); 236 | } 237 | 238 | while (*b && isspace(*b)) b++; 239 | memmove(p->buffer, b, strlen(b)+1); 240 | return 1; 241 | } 242 | 243 | if (*b == '"') { 244 | b++; a = p->value; 245 | while (*b && *b != '"' && *b != '\r' && *b != '\n') { 246 | if (*b == '\\') { 247 | b++; 248 | switch (*b) { 249 | case 'n': *a = '\n'; break; 250 | case 'r': *a = '\r'; break; 251 | case 't': *a = '\t'; break; 252 | default: *a = *b; 253 | } 254 | a++; b++; 255 | } else *a++ = *b++; 256 | } 257 | *a = '\0'; 258 | if (*b == '"') b++; 259 | else logger(LOG_WARNING, "%s:%i: unterminated string literal", p->file, p->line); 260 | 261 | p->token = T_STRING; 262 | while (*b && isspace(*b)) b++; 263 | memmove(p->buffer, b, strlen(b)+1); 264 | return 1; 265 | } 266 | 267 | if (*b == '@') { 268 | int n = 0; 269 | while (*b == '@') { n++; b++; } 270 | if (n > 2) { 271 | p->token = T_TOPIC; 272 | while (*b && isspace(*b)) b++; 273 | a = b; 274 | while (*b && !isspace(*b)) b++; 275 | *b++ = '\0'; 276 | memcpy(p->value, a, b-a); 277 | 278 | while (*b && isspace(*b)) b++; 279 | memmove(p->buffer, b, strlen(b)+1); 280 | return 1; 281 | } 282 | b = a; 283 | } 284 | 285 | 286 | logger(LOG_ERR, "%s:%i: failed to parse '%s'", p->file, p->line, p->buffer); 287 | return 0; 288 | } 289 | 290 | static int parse(void) 291 | { 292 | parser_t p; 293 | memset(&p, 0, sizeof(p)); 294 | p.file = strdup(""); 295 | p.io = stdin; 296 | 297 | op_t *FN = NULL; 298 | list_init(&OPS); 299 | 300 | #define NEXT if (!lex(&p)) { logger(LOG_CRIT, "%s:%i: unexpected end of configuration\n", p.file, p.line); goto bail; } 301 | #define ERROR(s) do { logger(LOG_CRIT, "%s:%i: syntax error: %s", p.file, p.line, s); goto bail; } while (0) 302 | 303 | int i, j; 304 | op_t *op; 305 | while (lex(&p)) { 306 | 307 | if (!p.value[0]) 308 | fprintf(stderr, "%02x %-14s\n", p.token, T_names[p.token]); 309 | else if (p.token == T_OPCODE) 310 | fprintf(stderr, "%02x %-14s : %#04x (%s)\n", p.token, T_names[p.token], 311 | p.value[0] & 0xff, ASM[(p.value[0] & 0xff) - T_OPCODE_NOOP]); 312 | else 313 | fprintf(stderr, "%02x %-14s : %s\n", p.token, T_names[p.token], p.value); 314 | 315 | op = calloc(1, sizeof(op_t)); 316 | op->fn = FN; 317 | 318 | switch (p.token) { 319 | case T_TOPIC: 320 | break; 321 | 322 | case T_FUNCTION: 323 | if (FN && list_tail(&OPS, op_t, l)->op != RET) { 324 | op->op = RET; 325 | list_push(&OPS, &op->l); 326 | op = calloc(1, sizeof(op_t)); 327 | } 328 | FN = op; 329 | op->special = SPECIAL_FUNC; 330 | NEXT; 331 | if (p.token != T_IDENTIFIER) 332 | ERROR("unacceptable name for function"); 333 | op->label = strdup(p.value); 334 | break; 335 | 336 | case T_LABEL: 337 | op->special = SPECIAL_LABEL; 338 | op->label = strdup(p.value); 339 | break; 340 | 341 | case T_OPCODE: 342 | for (i = 0; ASM_SYNTAX[i].token; i++) { 343 | if (p.value[0] != ASM_SYNTAX[i].token) continue; 344 | op->op = ASM_SYNTAX[i].opcode; 345 | 346 | for (j = 0; j < 2; j++) { 347 | if (ASM_SYNTAX[i].args[j] == ARG_NONE) break; 348 | NEXT; 349 | 350 | if (p.token == T_REGISTER && ASM_SYNTAX[i].args[j] & ARG_REGISTER) { 351 | op->args[j].type = VALUE_REGISTER; 352 | op->args[j]._.regname = p.value[0]; 353 | 354 | } else if (p.token == T_NUMBER && ASM_SYNTAX[i].args[j] & ARG_NUMBER) { 355 | op->args[j].type = VALUE_NUMBER; 356 | op->args[j]._.literal = strtol(p.value, NULL, 0); 357 | 358 | } else if (p.token == T_STRING && ASM_SYNTAX[i].args[j] & ARG_STRING) { 359 | op->args[j].type = VALUE_STRING; 360 | op->args[j]._.string = strdup(p.value); 361 | 362 | } else if (p.token == T_IDENTIFIER && ASM_SYNTAX[i].args[j] & ARG_LABEL) { 363 | op->args[j].type = VALUE_LABEL; 364 | op->args[j]._.label = strdup(p.value); 365 | 366 | } else if (p.token == T_IDENTIFIER && ASM_SYNTAX[i].args[j] & ARG_FUNCTION) { 367 | op->args[j].type = VALUE_FNLABEL; 368 | op->args[j]._.fnlabel = strdup(p.value); 369 | 370 | } else if (p.token == T_OFFSET && ASM_SYNTAX[i].args[j] & ARG_LABEL) { 371 | op->args[j].type = VALUE_OFFSET; 372 | op->args[j]._.offset = strtol(p.value, NULL, 10); 373 | 374 | } else { 375 | logger(LOG_CRIT, "%s: %i: invalid form; expected `%s`", 376 | p.file, p.line, ASM_SYNTAX[i].usage); 377 | goto bail; 378 | } 379 | } 380 | break; 381 | } 382 | break; 383 | 384 | case T_REGISTER: ERROR("unexpected register reference found at top-level"); 385 | case T_IDENTIFIER: ERROR("unexpected identifier found at top-level"); 386 | case T_OFFSET: ERROR("unexpected offset found at top-level"); 387 | case T_NUMBER: ERROR("unexpected numeric literal found at top-level"); 388 | case T_STRING: ERROR("unexpected string literal found at top-level"); 389 | 390 | default: 391 | ERROR("unhandled token type"); 392 | } 393 | 394 | list_push(&OPS, &op->l); 395 | } 396 | 397 | if (FN && list_tail(&OPS, op_t, l)->op != RET) { 398 | op = calloc(1, sizeof(op_t)); 399 | op->op = RET; 400 | list_push(&OPS, &op->l); 401 | } 402 | return 0; 403 | 404 | bail: 405 | return 1; 406 | } 407 | 408 | hash_t strings; 409 | static int s_resolve(value_t *v, op_t *me) 410 | { 411 | byte_t *addr; 412 | size_t len; 413 | op_t *op, *fn; 414 | 415 | switch (v->type) { 416 | case VALUE_REGISTER: 417 | v->bintype = TYPE_REGISTER; 418 | v->_.literal -= 'a'; 419 | return 0; 420 | 421 | case VALUE_NUMBER: 422 | v->bintype = TYPE_LITERAL; 423 | return 0; 424 | 425 | case VALUE_STRING: 426 | addr = hash_get(&strings, v->_.string); 427 | if (!addr) { 428 | len = strlen(v->_.string) + 1; 429 | if (STATIC.total - STATIC.used < len) { 430 | /* FIXME: only works for strings < STATIC.burst */ 431 | byte_t *mem = realloc(STATIC.mem, STATIC.total + STATIC.burst); 432 | if (!mem) perror("realloc"); 433 | 434 | STATIC.mem = mem; 435 | STATIC.total += STATIC.burst; 436 | } 437 | memcpy(STATIC.mem + STATIC.used, v->_.string, len); 438 | fprintf(stderr, "s_resolve: relocated string %s to %#010x\n", 439 | v->_.string, (unsigned)(STATIC.offset + STATIC.used)); 440 | 441 | addr = STATIC.mem + STATIC.used; 442 | hash_set(&strings, v->_.string, addr); 443 | STATIC.used += len; 444 | } 445 | 446 | free(v->_.string); 447 | 448 | v->type = VALUE_ADDRESS; 449 | v->bintype = TYPE_ADDRESS; 450 | v->_.address = STATIC.offset + (addr - STATIC.mem); 451 | return 0; 452 | 453 | case VALUE_ADDRESS: 454 | v->bintype = TYPE_ADDRESS; 455 | return 0; 456 | 457 | case VALUE_LABEL: 458 | fn = (op_t*)me->fn; 459 | for_each_object(op, &fn->l, l) { 460 | if (op->special == SPECIAL_FUNC) break; 461 | if (op->special != SPECIAL_LABEL) continue; 462 | if (strcmp(v->_.label, op->label) != 0) continue; 463 | 464 | free(v->_.label); 465 | v->type = VALUE_ADDRESS; 466 | v->bintype = TYPE_ADDRESS; 467 | v->_.address = op->offset; 468 | return 0; 469 | } 470 | logger(LOG_ERR, "label %s not found in scope!", v->_.label); 471 | return 1; 472 | 473 | case VALUE_FNLABEL: 474 | for_each_object(op, &me->l, l) { 475 | if (op->special != SPECIAL_FUNC) continue; 476 | if (strcmp(v->_.fnlabel, op->label) != 0) continue; 477 | 478 | free(v->_.fnlabel); 479 | v->type = VALUE_ADDRESS; 480 | v->bintype = TYPE_ADDRESS; 481 | v->_.address = op->offset; 482 | return 0; 483 | } 484 | logger(LOG_ERR, "fnlabel %s not found globally!", v->_.fnlabel); 485 | return 1; 486 | 487 | case VALUE_OFFSET: 488 | for_each_object(op, &me->l, l) { 489 | if (op->special) continue; 490 | if (v->_.offset--) continue; 491 | 492 | v->type = VALUE_ADDRESS; 493 | v->bintype = TYPE_ADDRESS; 494 | v->_.address = op->offset; 495 | return 0; 496 | } 497 | return 1; 498 | } 499 | return 0; 500 | } 501 | 502 | static int compile(void) 503 | { 504 | /* phases of compilation: 505 | 506 | I. insert runtime at addr 0 507 | II. determine offset of each opcode 508 | III. resolve labels / relative addresses 509 | IV. pack 'external memory' data 510 | V. encode 511 | */ 512 | 513 | memset(&STATIC, 0, sizeof(STATIC)); 514 | STATIC.burst = 256 * 1024; 515 | 516 | op_t *op; 517 | int rc; 518 | 519 | /* phase I: runtime insertion */ 520 | op = calloc(1, sizeof(op_t)); 521 | op->op = JMP; /* JMP, don't CALL */ 522 | op->args[0].type = VALUE_FNLABEL; 523 | op->args[0]._.label = strdup("main"); 524 | list_unshift(&OPS, &op->l); 525 | 526 | /* phase II: calculate offsets */ 527 | dword_t offset = 0; 528 | for_each_object(op, &OPS, l) { 529 | op->offset = offset; 530 | if (op->special) continue; 531 | offset += 2; /* 2-byte opcode */ 532 | if (op->args[0].type != VALUE_NONE) offset += 4; /* 4-byte operand */ 533 | if (op->args[1].type != VALUE_NONE) offset += 4; /* 4-byte operand */ 534 | } 535 | STATIC.offset = offset; 536 | CODE = calloc(offset, sizeof(byte_t)); 537 | byte_t *c = CODE; 538 | 539 | for_each_object(op, &OPS, l) { 540 | if (op->special) continue; 541 | 542 | /* phase II/III: resolve labels / pack strings */ 543 | rc = s_resolve(&op->args[0], op); 544 | assert(rc == 0); 545 | rc = s_resolve(&op->args[1], op); 546 | assert(rc == 0); 547 | 548 | /* phase IV: encode */ 549 | *c++ = op->op; 550 | *c++ = ((op->args[0].bintype & 0xff) << 4) 551 | | ((op->args[1].bintype & 0xff)); 552 | 553 | if (op->args[0].type) { 554 | *c++ = ((op->args[0]._.literal >> 24) & 0xff); 555 | *c++ = ((op->args[0]._.literal >> 16) & 0xff); 556 | *c++ = ((op->args[0]._.literal >> 8) & 0xff); 557 | *c++ = ((op->args[0]._.literal >> 0) & 0xff); 558 | } 559 | if (op->args[1].type) { 560 | *c++ = ((op->args[1]._.literal >> 24) & 0xff); 561 | *c++ = ((op->args[1]._.literal >> 16) & 0xff); 562 | *c++ = ((op->args[1]._.literal >> 8) & 0xff); 563 | *c++ = ((op->args[1]._.literal >> 0) & 0xff); 564 | } 565 | } 566 | 567 | return 0; 568 | } 569 | 570 | int main(int argc, char **argv) 571 | { 572 | log_open("asm", "console"); 573 | 574 | int rc = parse(); 575 | assert(rc == 0); 576 | 577 | rc = compile(); 578 | assert(rc == 0); 579 | 580 | op_t *op; 581 | for_each_object(op, &OPS, l) { 582 | fprintf(stderr, "%08x [%04x] %s\n", op->offset, op->op, OPCODES[op->op]); 583 | if (op->args[0].type != VALUE_NONE) { 584 | fprintf(stderr, "%8s 1: %s (%i)\n", " ", VTYPES[op->args[0].type], op->args[0].type); 585 | switch (op->args[0].type) { 586 | case VALUE_NUMBER: fprintf(stderr, "%11s= %i\n", " ", op->args[0]._.literal); break; 587 | case VALUE_LABEL: fprintf(stderr, "%11s @%s\n", " ", op->args[0]._.label); break; 588 | case VALUE_STRING: fprintf(stderr, "%11s \"%s\"\n", " ", op->args[0]._.string); break; 589 | case VALUE_ADDRESS: fprintf(stderr, "%11s %#010x\n", " ", op->args[0]._.address); break; 590 | } 591 | } 592 | if (op->args[1].type != VALUE_NONE) { 593 | fprintf(stderr, "%8s 2: %s (%i)\n", " ", VTYPES[op->args[1].type], op->args[1].type); 594 | switch (op->args[1].type) { 595 | case VALUE_NUMBER: fprintf(stderr, "%11s= %i\n", " ", op->args[1]._.literal); break; 596 | case VALUE_LABEL: fprintf(stderr, "%11s @%s\n", " ", op->args[1]._.label); break; 597 | case VALUE_STRING: fprintf(stderr, "%11s \"%s\"\n", " ", op->args[1]._.string); break; 598 | case VALUE_ADDRESS: fprintf(stderr, "%11s %0#10x\n", " ", op->args[1]._.address); break; 599 | } 600 | } 601 | fprintf(stderr, "\n"); 602 | } 603 | 604 | write(1, CODE, STATIC.offset); 605 | write(1, STATIC.mem, STATIC.used); 606 | 607 | return 0; 608 | } 609 | -------------------------------------------------------------------------------- /regm/file.p: -------------------------------------------------------------------------------- 1 | ; these are comments 2 | 3 | fn res.file.absent 4 | fs.stat %a 5 | jz +1 6 | retv 0 7 | 8 | fs.file? %a 9 | jz rm 10 | 11 | fs.symlink? %a 12 | jz rm 13 | 14 | err "%s exists, but is not a regular file" 15 | bail 16 | 17 | rm: 18 | fs.unlink %a 19 | jnz +2 20 | mark 21 | retv 0 22 | 23 | perror "failed to remove %s" 24 | bail 25 | 26 | fn res.file.present 27 | fs.stat %a 28 | jnz create 29 | 30 | fs.symlink? %a 31 | jz remove 32 | 33 | err "%s exists, but is not a regular file" 34 | bail 35 | 36 | remove: 37 | fs.unlink %a 38 | jz create 39 | 40 | perror "failed to replace %s with a regular file" 41 | bail 42 | 43 | create: 44 | fs.touch %a 45 | jnz +2 46 | mark 47 | retv 0 48 | 49 | perror "failed to create regular file %s" 50 | bail 51 | 52 | fn res.file.chown 53 | getuid %b %c 54 | jz ok 55 | 56 | ; re-arrange registers for err call 57 | set %a %b ; %a is now the username, too 58 | err "failed to find user %s" 59 | bail 60 | 61 | ok: 62 | fs.chown %a %c 63 | jnz +2 64 | mark 65 | retv 0 66 | 67 | perror "failed to change ownership of %s to %s" 68 | bail 69 | 70 | fn res.file.chgrp 71 | getgid %b %c 72 | jz ok 73 | 74 | ; re-arrange registers for err call 75 | set %a %b ; %a is now the group name, too 76 | err "failed to find group %s" 77 | bail 78 | 79 | ok: 80 | fs.chgrp %a %c 81 | jnz +2 82 | mark 83 | retv 0 84 | 85 | perror "failed to change group ownership of %s to %s: %s" 86 | bail 87 | 88 | fn res.file.chmod 89 | fs.chmod %a %b 90 | jnz +2 91 | mark 92 | retv 0 93 | 94 | perror "failed to set mode of %s to %04o: %s" 95 | bail 96 | 97 | fn res.file.diff 98 | ; %a is path 99 | ; %b is remote sha1 100 | 101 | fs.sha1 %a %p 102 | jz +2 103 | perror "failed to calculate SHA1 for local copy of %s" 104 | bail 105 | 106 | strcmp %b %p 107 | ret 108 | 109 | fn res.file.update 110 | ; %a is path 111 | ; %b is remote sha1 112 | ; %c is cached/not 113 | 114 | getfile %b %a 115 | jnz +1 116 | ret 117 | 118 | err "failed to update contents of %s" 119 | bail 120 | 121 | fn res.file.verify 122 | ; %a is temp path 123 | ; %b is real path 124 | ; %c is verify command 125 | ; %d is expected rc 126 | 127 | push %b 128 | push %a 129 | 130 | set %a 0 ; run as user root 131 | set %b 0 ; run as group root 132 | 133 | exec %c %e 134 | cmp %d %e 135 | jz +1 136 | ret 137 | 138 | pop %a 139 | pop %b 140 | fs.rename %a %b 141 | jnz +1 142 | retv 0 143 | 144 | fs.unlink %a 145 | perror "failed to rename %s to %s" 146 | bail 147 | 148 | fn res.file.contents 149 | ; %a is path 150 | ; %b is remote sha1 151 | ; %c is cached/not 152 | ; %d is verify/not 153 | ; %e is verify command 154 | ; %f is expected rc 155 | ; %g is tempfile 156 | 157 | call res.file.diff 158 | jnz +1 159 | ret 160 | 161 | ;; files differ 162 | cmp %d 1 ; should we use %g (tempfile) 163 | jnz update ; in place of %a (real path)? 164 | 165 | swap %g %a ; yes. update the contents of 166 | ; the tempfile first, so we can 167 | ; run the verify (%e) command 168 | 169 | update: 170 | call res.file.update ; no need to check return value 171 | ; res.file.update will bail if 172 | ; there were any problems 173 | 174 | cmp %d 1 ; run the verification? 175 | jz verify 176 | mark 177 | ret 178 | 179 | verify: 180 | set %b %g ; real path 181 | set %c %e ; verify command 182 | set %d %f ; expected rc 183 | 184 | call res.file.verify ; no need to check return value 185 | ; res.file.verify will bail if 186 | ; there are any problems 187 | mark 188 | retv 0 189 | 190 | fn main 191 | @@@ file:/path/to/delete 192 | set %a "/path/to/delete" 193 | call res.file.absent 194 | 195 | @@@ file:/etc/sudoers 196 | set %a "/etc/sudoers" 197 | call res.file.present 198 | 199 | ;;udbopen 200 | set %b "root" 201 | call res.file.chown 202 | set %b "root" 203 | call res.file.chgrp 204 | ;;udbclose 205 | 206 | set %b 0755 207 | call res.file.chmod 208 | 209 | set %b "decafbadcafe" ; rsha1 210 | set %c 1 ; cached 211 | set %d 1 ; do verify 212 | set %e "/bin/test-it -c /tmp/file" 213 | set %f 0 214 | set %g "/tmp/file" 215 | call res.file.contents 216 | -------------------------------------------------------------------------------- /regm/gencode: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use YAML::XS qw/LoadFile/; 7 | use List::Util qw/max/; 8 | 9 | my @cols = (); 10 | my @widths = (); 11 | sub column 12 | { 13 | @_ = map { "$_," } @_; 14 | if (!@cols) { 15 | @widths = map { 0 } @_; 16 | } else { 17 | for (my $i = 0; $i < @_; $i++) { 18 | $widths[$i] = max($widths[$i], length $_[$i]); 19 | } 20 | } 21 | 22 | push @cols, [@_]; 23 | } 24 | 25 | sub table 26 | { 27 | my ($fmt) = @_; 28 | $fmt =~ s/%s/%-${_}s/ for @widths; 29 | printf $fmt, @$_ for @cols; 30 | } 31 | 32 | sub arg 33 | { 34 | my ($list, $reg) = @_; 35 | return ("", "ARG_NONE") if !$list || !@$list; 36 | 37 | my (@names, @flags); 38 | for (@$list) { 39 | if (m/register/) { 40 | push @names, $reg; 41 | push @flags, "ARG_REGISTER"; 42 | } elsif (m/(number|string|function|label)/) { 43 | push @names, "<$1>"; 44 | push @flags, uc("ARG_$1"); 45 | } else { 46 | die "Unhandled arg type $_\n"; 47 | } 48 | } 49 | 50 | return ((@names == 1 ? " $names[0]" : " (".join('|', @names).")"), join('|', @flags)); 51 | } 52 | 53 | my $lst = eval { LoadFile "opcodes.yml" } 54 | or die "Failed to load opcoes.yml: $!\n"; 55 | 56 | for my $op (@$lst) { 57 | my ($key, $o) = %$op; 58 | if (!$o->{constant}) { 59 | $o->{constant} = uc($key); 60 | $o->{constant} =~ s/\./_/g; 61 | $o->{constant} =~ s/\?$/_P/g; 62 | } 63 | 64 | $o->{opcode} = uc($o->{alias} || $o->{constant}); 65 | 66 | my ($name, $flags); 67 | my $usage; 68 | 69 | $usage = $key; 70 | ($name, $flags) = arg($o->{args}[0], "%a"); 71 | $usage .= $name; $o->{args}[0] = $flags; 72 | 73 | ($name, $flags) = arg($o->{args}[1], "%b"); 74 | $usage .= $name; $o->{args}[1] = $flags; 75 | 76 | $o->{usage} = $usage if !$o->{usage}; 77 | } 78 | 79 | my $n = 0; 80 | my $len = 0; 81 | for my $op (@$lst) { 82 | my ($key, $o) = %$op; 83 | $len = max($len, length($o->{constant})); 84 | $n++; 85 | } 86 | 87 | $n = 0; 88 | print "/* opcodes.h - generated by gencode */\n\n"; 89 | print "/** OPCODE CONSTANTS **/\n"; 90 | for my $op (@$lst) { 91 | my ($key, $o) = %$op; 92 | next if $o->{alias}; 93 | printf "#define %-${len}s %#04x /* %s */\n", $o->{constant}, $n++, $o->{help}; 94 | } 95 | 96 | print "\n\n"; 97 | print "#ifdef OPCODES_EXTENDED\n"; 98 | print "/** OPCODE MNEMONIC NAMES **/\n"; 99 | print "static const char * OPCODES[] = {\n"; 100 | $n = 0; 101 | for my $op (@$lst) { 102 | my ($key, $o) = %$op; 103 | next if $o->{alias}; 104 | printf qq(\t%-@{[$len+3]}s /* %-${len}s %2i %#04x */\n), qq("$key",), $o->{constant}, $n, $n; 105 | $n++; 106 | } 107 | print "\tNULL,\n"; 108 | print "};\n"; 109 | 110 | print "\n\n"; 111 | print "/** ASM TOKENS **/\n"; 112 | $n = 0x40; 113 | for my $op (@$lst) { 114 | my ($key, $o) = %$op; 115 | printf "#define T_OPCODE_%-${len}s %#04x /* %s */\n", $o->{constant}, $n++, $o->{help}; 116 | } 117 | 118 | print "\n\n"; 119 | print "static const char * ASM[] = {\n"; 120 | $n = 0; 121 | for my $op (@$lst) { 122 | my ($key, $o) = %$op; 123 | printf qq(\t%-@{[$len+3]}s /* T_OPCODE_%-${len}s %2i %#04x */\n), qq("$key",), $o->{constant}, $n, $n; 124 | $n++; 125 | } 126 | print "\tNULL,\n"; 127 | print "};\n\n"; 128 | 129 | print <{constant}", qq("$o->{usage}"), $o->{opcode}, $o->{args}[0], $o->{args}[1]; 148 | } 149 | table "\t{ %s %s %s { %s %s } },\n"; 150 | print "\t{ 0, 0, 0, { 0, 0 } },\n"; 151 | print "};\n\n"; 152 | 153 | print "#endif\n"; 154 | -------------------------------------------------------------------------------- /regm/opcodes.h: -------------------------------------------------------------------------------- 1 | /* opcodes.h - generated by gencode */ 2 | 3 | /** OPCODE CONSTANTS **/ 4 | #define NOOP 0000 /* does nothing */ 5 | #define PUSH 0x01 /* push a register onto data stack */ 6 | #define POP 0x02 /* pop data stack top into a register */ 7 | #define SET 0x03 /* set register value */ 8 | #define SWAP 0x04 /* swap two register values */ 9 | #define ADD 0x05 /* add the second operand to the first */ 10 | #define SUB 0x06 /* subtract the second operand from the first */ 11 | #define MULT 0x07 /* multiply the first operand by the second */ 12 | #define DIV 0x08 /* divide the first operand by the second */ 13 | #define MOD 0x09 /* modulo the first operand by the second */ 14 | #define CALL 0x0a /* call a user-defined function */ 15 | #define RET 0x0b /* return to caller */ 16 | #define CMP 0x0c /* compare two integers */ 17 | #define STRCMP 0x0d /* compare two strings */ 18 | #define JMP 0x0e /* unconditional jump */ 19 | #define JZ 0x0f /* jump if accumulator is 0 */ 20 | #define JNZ 0x10 /* jump if accumulator is not 0 */ 21 | #define JE 0x11 /* jump if accumulator is equal to first operand */ 22 | #define JNE 0x12 /* jump if accumulator is not equal to first operand */ 23 | #define JGT 0x13 /* jump if accumulator is greater than first operand */ 24 | #define JGTE 0x14 /* jump if accumulator is greater than or equal to first operand */ 25 | #define JLT 0x15 /* jump if accumulator is less than first operand */ 26 | #define JLTE 0x16 /* jump if accumulator is less than or equal to first operand */ 27 | #define STRING 0x17 /* format a (heap-allocated) string */ 28 | #define PRINT 0x18 /* print a message to standard output */ 29 | #define DUMP 0x19 /* dump virtual machine state for debugging */ 30 | #define HALT 0x1a /* halt the virtual machine */ 31 | 32 | 33 | #ifdef OPCODES_EXTENDED 34 | /** OPCODE MNEMONIC NAMES **/ 35 | static const char * OPCODES[] = { 36 | "noop", /* NOOP 0 0000 */ 37 | "push", /* PUSH 1 0x01 */ 38 | "pop", /* POP 2 0x02 */ 39 | "set", /* SET 3 0x03 */ 40 | "swap", /* SWAP 4 0x04 */ 41 | "add", /* ADD 5 0x05 */ 42 | "sub", /* SUB 6 0x06 */ 43 | "mult", /* MULT 7 0x07 */ 44 | "div", /* DIV 8 0x08 */ 45 | "mod", /* MOD 9 0x09 */ 46 | "call", /* CALL 10 0x0a */ 47 | "ret", /* RET 11 0x0b */ 48 | "cmp", /* CMP 12 0x0c */ 49 | "strcmp", /* STRCMP 13 0x0d */ 50 | "jmp", /* JMP 14 0x0e */ 51 | "jz", /* JZ 15 0x0f */ 52 | "jnz", /* JNZ 16 0x10 */ 53 | "je", /* JE 17 0x11 */ 54 | "jne", /* JNE 18 0x12 */ 55 | "jgt", /* JGT 19 0x13 */ 56 | "jgte", /* JGTE 20 0x14 */ 57 | "jlt", /* JLT 21 0x15 */ 58 | "jlte", /* JLTE 22 0x16 */ 59 | "string", /* STRING 23 0x17 */ 60 | "print", /* PRINT 24 0x18 */ 61 | "dump", /* DUMP 25 0x19 */ 62 | "halt", /* HALT 26 0x1a */ 63 | NULL, 64 | }; 65 | 66 | 67 | /** ASM TOKENS **/ 68 | #define T_OPCODE_NOOP 0x40 /* does nothing */ 69 | #define T_OPCODE_PUSH 0x41 /* push a register onto data stack */ 70 | #define T_OPCODE_POP 0x42 /* pop data stack top into a register */ 71 | #define T_OPCODE_SET 0x43 /* set register value */ 72 | #define T_OPCODE_SWAP 0x44 /* swap two register values */ 73 | #define T_OPCODE_ADD 0x45 /* add the second operand to the first */ 74 | #define T_OPCODE_SUB 0x46 /* subtract the second operand from the first */ 75 | #define T_OPCODE_MULT 0x47 /* multiply the first operand by the second */ 76 | #define T_OPCODE_DIV 0x48 /* divide the first operand by the second */ 77 | #define T_OPCODE_MOD 0x49 /* modulo the first operand by the second */ 78 | #define T_OPCODE_CALL 0x4a /* call a user-defined function */ 79 | #define T_OPCODE_RET 0x4b /* return to caller */ 80 | #define T_OPCODE_RETV 0x4c /* return to caller (with value) */ 81 | #define T_OPCODE_CMP 0x4d /* compare two integers */ 82 | #define T_OPCODE_STRCMP 0x4e /* compare two strings */ 83 | #define T_OPCODE_JMP 0x4f /* unconditional jump */ 84 | #define T_OPCODE_JZ 0x50 /* jump if accumulator is 0 */ 85 | #define T_OPCODE_JNZ 0x51 /* jump if accumulator is not 0 */ 86 | #define T_OPCODE_JE 0x52 /* jump if accumulator is equal to first operand */ 87 | #define T_OPCODE_JNE 0x53 /* jump if accumulator is not equal to first operand */ 88 | #define T_OPCODE_JGT 0x54 /* jump if accumulator is greater than first operand */ 89 | #define T_OPCODE_JGTE 0x55 /* jump if accumulator is greater than or equal to first operand */ 90 | #define T_OPCODE_JLT 0x56 /* jump if accumulator is less than first operand */ 91 | #define T_OPCODE_JLTE 0x57 /* jump if accumulator is less than or equal to first operand */ 92 | #define T_OPCODE_STRING 0x58 /* format a (heap-allocated) string */ 93 | #define T_OPCODE_PRINT 0x59 /* print a message to standard output */ 94 | #define T_OPCODE_DUMP 0x5a /* dump virtual machine state for debugging */ 95 | #define T_OPCODE_HALT 0x5b /* halt the virtual machine */ 96 | 97 | 98 | static const char * ASM[] = { 99 | "noop", /* T_OPCODE_NOOP 0 0000 */ 100 | "push", /* T_OPCODE_PUSH 1 0x01 */ 101 | "pop", /* T_OPCODE_POP 2 0x02 */ 102 | "set", /* T_OPCODE_SET 3 0x03 */ 103 | "swap", /* T_OPCODE_SWAP 4 0x04 */ 104 | "add", /* T_OPCODE_ADD 5 0x05 */ 105 | "sub", /* T_OPCODE_SUB 6 0x06 */ 106 | "mult", /* T_OPCODE_MULT 7 0x07 */ 107 | "div", /* T_OPCODE_DIV 8 0x08 */ 108 | "mod", /* T_OPCODE_MOD 9 0x09 */ 109 | "call", /* T_OPCODE_CALL 10 0x0a */ 110 | "ret", /* T_OPCODE_RET 11 0x0b */ 111 | "retv", /* T_OPCODE_RETV 12 0x0c */ 112 | "cmp", /* T_OPCODE_CMP 13 0x0d */ 113 | "strcmp", /* T_OPCODE_STRCMP 14 0x0e */ 114 | "jmp", /* T_OPCODE_JMP 15 0x0f */ 115 | "jz", /* T_OPCODE_JZ 16 0x10 */ 116 | "jnz", /* T_OPCODE_JNZ 17 0x11 */ 117 | "je", /* T_OPCODE_JE 18 0x12 */ 118 | "jne", /* T_OPCODE_JNE 19 0x13 */ 119 | "jgt", /* T_OPCODE_JGT 20 0x14 */ 120 | "jgte", /* T_OPCODE_JGTE 21 0x15 */ 121 | "jlt", /* T_OPCODE_JLT 22 0x16 */ 122 | "jlte", /* T_OPCODE_JLTE 23 0x17 */ 123 | "string", /* T_OPCODE_STRING 24 0x18 */ 124 | "print", /* T_OPCODE_PRINT 25 0x19 */ 125 | "dump", /* T_OPCODE_DUMP 26 0x1a */ 126 | "halt", /* T_OPCODE_HALT 27 0x1b */ 127 | NULL, 128 | }; 129 | 130 | #define ARG_NONE 0x00 131 | #define ARG_REGISTER 0x01 132 | #define ARG_NUMBER 0x02 133 | #define ARG_STRING 0x04 134 | #define ARG_LABEL 0x08 135 | #define ARG_FUNCTION 0x10 136 | 137 | static struct { 138 | byte_t token; 139 | const char *usage; 140 | byte_t opcode; 141 | byte_t args[2]; 142 | } ASM_SYNTAX[] = { 143 | { T_OPCODE_NOOP, "noop", NOOP, { ARG_NONE, ARG_NONE, } }, 144 | { T_OPCODE_PUSH, "push %a", PUSH, { ARG_REGISTER, ARG_NONE, } }, 145 | { T_OPCODE_POP, "pop %a", POP, { ARG_REGISTER, ARG_NONE, } }, 146 | { T_OPCODE_SET, "set %a (%b||)", SET, { ARG_REGISTER, ARG_REGISTER|ARG_STRING|ARG_NUMBER, } }, 147 | { T_OPCODE_SWAP, "swap %a %b", SWAP, { ARG_REGISTER, ARG_REGISTER, } }, 148 | { T_OPCODE_ADD, "add %a (%b|)", ADD, { ARG_REGISTER, ARG_REGISTER|ARG_NUMBER, } }, 149 | { T_OPCODE_SUB, "sub %a (%b|)", SUB, { ARG_REGISTER, ARG_REGISTER|ARG_NUMBER, } }, 150 | { T_OPCODE_MULT, "mult %a (%b|)", MULT, { ARG_REGISTER, ARG_REGISTER|ARG_NUMBER, } }, 151 | { T_OPCODE_DIV, "div %a (%b|)", DIV, { ARG_REGISTER, ARG_REGISTER|ARG_NUMBER, } }, 152 | { T_OPCODE_MOD, "mod %a (%b|)", MOD, { ARG_REGISTER, ARG_REGISTER|ARG_NUMBER, } }, 153 | { T_OPCODE_CALL, "call ", CALL, { ARG_FUNCTION, ARG_NONE, } }, 154 | { T_OPCODE_RET, "ret", RET, { ARG_NONE, ARG_NONE, } }, 155 | { T_OPCODE_RETV, "retv (%a||)", RET, { ARG_REGISTER|ARG_STRING|ARG_NUMBER, ARG_NONE, } }, 156 | { T_OPCODE_CMP, "cmp (%a|) (%b|)", CMP, { ARG_REGISTER|ARG_NUMBER, ARG_REGISTER|ARG_NUMBER, } }, 157 | { T_OPCODE_STRCMP, "strcmp (%a|) (%b|)", STRCMP, { ARG_REGISTER|ARG_STRING, ARG_REGISTER|ARG_STRING, } }, 158 | { T_OPCODE_JMP, "jmp