LoginSignup
0
1

x86_64アセンブラに落とすbrainfuckコンパイラ in C and python

Last updated at Posted at 2024-02-15

Brainfuckソースをアセンブラに変換するコンパイラbfs

cc bfs.c -o bfsとしてコンパイルしてください。

./bfs file.bfとすると、file.bfからbrainfuckのソースを読み込み、x86_64アセンブラに変換して標準出力に出力します。リダイレクトしてご使用ください。
for ex.
./bfs file.bf >file.s
出力されたソースはccの出力する.sファイルと同様ですので、
cc file.s
とするとa.outに実行コードが出力されます。

bfs.c
#include    <stdio.h>
#include    <stdlib.h>
static int loopstack[1000];
static int lsp=0;

void lsout() {
    for (int i=0;i<lsp;i++)
        printf("%d_",loopstack[i]);
}

void main(int argc,char *argv[]) {
    FILE *fp;
    int  c,lf;
    if (argc!=2) {
        fprintf(stderr,"Usage: bfs <file>\n");
        exit(1);
    }
    fp=fopen(argv[1],"rt");
    if (fp==NULL) {
        fprintf(stderr,"File open error.\n");
        exit(1);
    }

    printf("\t.file\t\"%s\"\n",argv[1]);
	printf("\t.text\n");
	printf("\t.globl\tmain\n");
	printf("\t.type\tmain,@function\n");
    printf("main:\n");
    printf(".LFB0:\n");
    printf("\t.cfi_startproc\n");
	printf("\tpushq\t%%rbp\n");
	printf("\t.cfi_def_cfa_offset 16\n");
	printf("\t.cfi_offset 6, -16\n");
	printf("\tmovq\t%%rsp, %%rbp\n");
	printf("\t.cfi_def_cfa_register 6\n");
	printf("\tsubq\t$30032, %%rsp\n");
	printf("\tmovq\t%%fs:40, %%rax\n");
	printf("\tmovq\t%%rax, -8(%%rbp)\n");
	printf("\txorl\t%%eax, %%eax\n");
	printf("\tleaq\t-30016(%%rbp), %%rax\n");
	printf("\tmovl\t$30000, %%edx\n");
	printf("\tmovl\t$0, %%esi\n");
	printf("\tmovq\t%%rax, %%rdi\n");
	printf("\tcall\tmemset@PLT\n");
	printf("\tleaq\t-30016(%%rbp), %%rax\n");
	printf("\tmovq\t%%rax, -30024(%%rbp)\n");

    lsp=0;
    lf='[';
    while((c=fgetc(fp))!=EOF) {
        switch (c) {
            case '>':
                printf("\taddq\t$1, -30024(%%rbp)\n");
                break;
            case '<':
                printf("\tsubq\t$1, -30024(%%rbp)\n");
                break;
            case '+':
				printf("\tmovq\t-30024(%%rbp), %%rax\n");
				printf("\tmovzbl\t(%%rax), %%eax\n");
				printf("\taddl\t$1, %%eax\n");
				printf("\tmovl\t%%eax, %%edx\n");
				printf("\tmovq\t-30024(%%rbp), %%rax\n");
				printf("\tmovb\t%%dl, (%%rax)\n");
                break;
            case '-':
				printf("\tmovq\t-30024(%%rbp), %%rax\n");
				printf("\tmovzbl\t(%%rax), %%eax\n");
				printf("\tsubl\t$1, %%eax\n");
				printf("\tmovl\t%%eax, %%edx\n");
				printf("\tmovq\t-30024(%%rbp), %%rax\n");
				printf("\tmovb\t%%dl, (%%rax)\n");
                break;
            case '.':
				printf("\tmovq\t-30024(%%rbp), %%rax\n");
				printf("\tmovzbl\t(%%rax), %%eax\n");
				printf("\tmovsbl\t%%al, %%eax\n");
				printf("\tmovl\t%%eax, %%edi\n");
				printf("\tcall\tputchar@PLT\n");
                break;
            case ',':
				printf("\tcall	getchar@PLT\n");
				printf("\tmovl	%%eax, %%edx\n");
				printf("\tmovq	-30024(%%rbp), %%rax\n");
				printf("\tmovb	%%dl, (%%rax)\n");
                break;
            case '[':
                if (lf==']')
                    loopstack[(lsp-1)]++;
                else
                    loopstack[lsp++]=1;
                lf='[';
                printf("\tjmp LE"); lsout(); printf("\n");
                printf("LB"); lsout(); printf(":\n");
                break;
            case ']':
                if (lf==']')
                    lsp--;
                lf=']';
                printf("LE"); lsout(); printf(":\n");
                printf("\tmovq\t-30024(%%rbp), %%rax\n");
	            printf("\tmovzbl\t(%%rax), %%eax\n");
	            printf("\ttestb\t%%al, %%al\n");
                printf("\tjne\tLB"); lsout(); printf("\n");
                break;
            default:
            }
    }
    fclose(fp);
	printf("\tnop\n");
	printf("\tmovq\t-8(%%rbp), %%rax\n");
	printf("\tsubq\t%%fs:40, %%rax\n");
	printf("\tje\t.LFE1\n");
	printf("\tcall\t__stack_chk_fail@PLT\n");
	printf(".LFE1:\n");
	printf("\tleave\n");
	printf("\t.cfi_def_cfa 7, 8\n");
	printf("\tret\n");
	printf("\t.cfi_endproc\n");
	printf(".LFE0:\n");
	printf("\t.size\tmain, .-main\n");
	printf("\t.section\t.note.GNU-stack,\"\",@progbits\n");
    exit(0);
}

python版

こちらはpython3で書いたbfsです。
C版と同じコードを出力します。
使い方:
./bfs.py sample.bf >sample.s

bfs.py
#!/usr/bin/python3
import sys

def lsout(loopstack):
    return str(loopstack).replace(', ','_').replace('[','').replace(']','')

def main():
    if len(sys.argv)!=2:
        print(f"Usage: {sys.argv[0]} <file>")
        return

    print(f"\t.file\t\"{sys.argv[1]}\"")
    print("    .text")
    print("    .globl  main")
    print("    .type   main,@function")
    print("main:")
    print(".LFB0:")
    print("    .cfi_startproc")
    print("    pushq    %rbp")
    print("    .cfi_def_cfa_offset 16")
    print("    .cfi_offset 6, -16")
    print("    movq    %rsp, %rbp")
    print("    .cfi_def_cfa_register 6")
    print("    subq    $30032, %rsp")
    print("    movq    %fs:40, %rax")
    print("    movq    %rax, -8(%rbp)")
    print("    xorl    %eax, %eax")
    print("    leaq    -30016(%rbp), %rax")
    print("    movl    $30000, %edx")
    print("    movl    $0, %esi")
    print("    movq    %rax, %rdi")
    print("    call    memset@PLT")
    print("    leaq    -30016(%rbp), %rax")
    print("    movq    %rax, -30024(%rbp)")

    f=open(sys.argv[1],"rt")
    loopstack=[]
    lf='['
    for s in f:
        for c in s:
            if c=='>':
                print("    addq    $1, -30024(%rbp)")
            elif c=='<':
                print("    subq    $1, -30024(%rbp)")
            elif c=='+':
                print("    movq    -30024(%rbp), %rax")
                print("    movzbl  (%rax), %eax")
                print("    addl    $1, %eax")
                print("    movl    %eax, %edx")
                print("    movq    -30024(%rbp), %rax")
                print("    movb    %dl, (%rax)")
            elif c=='-':
                print("    movq    -30024(%rbp), %rax")
                print("    movzbl  (%rax), %eax")
                print("    subl    $1, %eax")
                print("    movl    %eax, %edx")
                print("    movq    -30024(%rbp), %rax")
                print("    movb    %dl, (%rax)")
            elif c=='.':
                print("    movq    -30024(%rbp), %rax")
                print("    movzbl  (%rax), %eax")
                print("    movsbl  %al, %eax")
                print("    movl    %eax, %edi")
                print("    call    putchar@PLT")
            elif c==',':
                print("    call    getchar@PLT")
                print("    movl    %eax, %edx")
                print("    movq    -30024(%rbp), %rax")
                print("    movb    %dl, (%rax)")
            elif c=='[':
                if lf==']':
                    loopstack[len(loopstack)-1]+=1
                else:
                    loopstack.append(1)
                lf='['
                print(f"    jmp     LE{lsout(loopstack)}")
                print(f"LB{lsout(loopstack)}:")
            elif c==']':
                if lf==']':
                    loopstack.pop()
                lf=']'
                print(f"LE{lsout(loopstack)}:")
                print("    movq    -30024(%rbp), %rax")
                print("    movzbl  (%rax), %eax")
                print("    testb   %al, %al")
                print(f"    jne     LB{lsout(loopstack)}")
    f.close()
    print("    nop")
    print("    movq    -8(%rbp), %rax")
    print("    subq    %fs:40, %rax")
    print("    je      .LFE1")
    print("    call    __stack_chk_fail@PLT")
    print(".LFE1:")
    print("    leave")
    print("    .cfi_def_cfa 7, 8")
    print("    ret")
    print("    .cfi_endproc")
    print(".LFE0:")
    print("    .size   main, .-main")
    print("    .section .note.GNU-stack,\"\",@progbits")

if __name__=='__main__':
    main()
    exit(0)


0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1