#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> void pasm(const char *s, ...); void syscall(const char *ncall, const char *a, const char *b, const char *c); int push(int n); int pop(void); void print_long(const char *name); void print_data(void); void print_getchar(void); void print_putchar(void); void init_bf(void); void out_sub(int val, char c, const char *to); void out_add(int val, char c, const char *to); void char_to_code(int c, int times); void pasm(const char *s, ...) { va_list args; printf("\t"); va_start(args, s); vprintf(s, args); va_end(args); printf("\n"); } #if defined(linux) || defined(__linux) void syscall(const char *ncall, const char *a, const char *b, const char *c) { if (strcmp("%eax", ncall)) // Here to avoid redundant movs pasm("movl %s, %%eax", ncall); if (strcmp("%ebx", a)) pasm("movl %s, %%ebx", a); if (strcmp("%ecx", b)) pasm("movl %s, %%ecx", b); if (strcmp("%edx", c)) pasm("movl %s, %%edx", c); pasm("int $0x80"); } #elif defined(BSD) // the BSD style syscall isn't tested void syscall(const char *ncall, const char *a, const char *b, const char *c) { pasm("movl %s, %%eax", ncall); pasm("pushl %s", c); pasm("pushl %s", b); pasm("pushl %s", a); pasm("subl $4, %%esp"); pasm("int $0x80"); pasm("addl $16, %%esp"); } #else # error only handles linux and bsd systems #endif typedef struct s_llst t_llst; struct s_llst { int n; t_llst *next; }; // The labels stack t_llst *stack = NULL; int label_max = 0; int push(int n) { t_llst *p; p = malloc(sizeof(*p)); p->n = n; p->next = stack; stack = p; return (n); } int pop() { int tmp_n; t_llst *p; if (stack == NULL) return (-1); tmp_n = stack->n; p = stack; stack = p->next; free(p); return (tmp_n); } void print_long(const char *name) { printf(".align 4\n"); printf("%s:\n", name); pasm(".long 0"); } void print_data() { printf(".data\n"); print_long("pos_read"); print_long("len_read"); print_long("pos_write"); puts(""); pasm(".comm buf_read, 512, 32"); pasm(".comm buf_write, 512, 32"); puts(""); } void print_getchar() { printf("getchar:\n"); pasm("movl pos_read, %%eax"); pasm("cmpl len_read, %%eax"); pasm("jl retchar"); syscall("$3", "$0", "$buf_read", "$512"); // The read syscall pasm("cmpl $0, %%eax"); // Note: that doesn't handle errors properly on bsd pasm("jg read_ok"); pasm("movl $0, (%%ebp, %%esi)"); // EOF is handled as returning 0 pasm("ret"); printf("read_ok:\n"); pasm("movl %%eax, len_read"); pasm("movl $0, pos_read"); printf("retchar:\n"); pasm("movl pos_read, %%eax"); pasm("movb buf_read(%%eax), %%bh"); pasm("movb %%bh, (%%ebp, %%esi)"); pasm("incl %%eax"); pasm("movl %%eax, pos_read"); pasm("ret"); } void print_putchar() { printf("putchar:\n"); pasm("movl pos_write, %%eax"); pasm("incl %%eax"); pasm("movb (%%ebp, %%esi), %%bh"); pasm("movb %%bh, buf_write(%%eax)"); pasm("movl %%eax, pos_write"); pasm("cmpl $512, %%eax"); pasm("jge flush"); pasm("cmpb $%d, %%bh", '\n'); pasm("je flush"); pasm("ret"); printf("flush:\n"); pasm("movl pos_write, %%edx"); pasm("incl %%edx"); syscall("$4", "$1", "$buf_write", "%edx"); pasm("movl $0, pos_write"); pasm("ret"); } void init_bf() { print_data(); printf(".text\n"); print_getchar(); print_putchar(); printf(".globl _start\n"); printf("_start:\n"); pasm("movl %%esp, %%ebp"); // base pointer pasm("subl $30000, %%esp"); // allocate space pasm("xorl %%eax, %%eax"); printf("memzero:\n"); // initialize space pasm("movl $0, (%%ebp, %%eax, 0x4)"); pasm("decl %%eax"); pasm("cmpl $-7500, %%eax"); pasm("jg memzero"); pasm("xorl %%esi, %%esi"); // initialize counter } void out_sub(int val, char c, const char *to) { if (val < 0) out_add(-val, c, to); else if (val == 1) pasm("dec%c %s", c, to); else if (val > 1) pasm("sub%c $%d, %s", c, val, to); } void out_add(int val, char c, const char *to) { if (val < 0) out_sub(-val, c, to); else if (val == 1) pasm("inc%c %s", c, to); else if (val > 1) pasm("add%c $%d, %s", c, val, to); } void char_to_code(int c, int times) { if (c == '>') // handles circular memory { out_sub(times, 'l', "%esi"); pasm("cmpl $-30000, %%esi"); pasm("jg wrapped%d", label_max); pasm("addl $30000, %%esi"); printf("wrapped%d:\n", label_max++); } else if (c == '<') { out_add(times, 'l', "%esi"); pasm("cmpl $0, %%esi"); pasm("jle wrapped%d", label_max); pasm("subl $30000, %%esi"); printf("wrapped%d:\n", label_max++); } else if (c == '+') out_add(times, 'b', "(%ebp, %esi)"); else if (c == '-') out_sub(times, 'b', "(%ebp, %esi)"); else if (c == '.') while (times--) pasm("call putchar"); else if (c == ',') while (times--) pasm("call getchar"); else if (c == '[') while (times--) { printf("start%d:\n", push(label_max++)); pasm("movb (%%ebp, %%esi), %%al"); pasm("testb %%al, %%al"); pasm("jz end%d", stack->n); } else if (c == ']') while (times--) { pasm("jmp start%d", stack->n); printf("end%d:\n", pop()); } } int main() { int cur_char; int last_char; int times_char; init_bf(); times_char = 0; last_char = cur_char = getchar(); do { if (cur_char == last_char) times_char++; else { char_to_code(last_char, times_char); last_char = cur_char; times_char = 1; } } while ((cur_char = getchar()) != -1); pasm("call flush"); pasm("movzbl (%%ebp, %%esi), %%ebx"); pasm("movl $1, %%eax"); pasm("int $0x80"); return (0); }