.set SYS_READ, 0 .set SYS_WRITE, 1 .set SYS_OPEN, 2 .set SYS_CLOSE, 3 .set SYS_BRK, 12 .set SYS_EXIT, 60 .set F_CREATE_AND_WRITE, 0x41 .set F_MODE_EXECUTABLE, 0744 .section translations, "a" t_init: mov $0x3001b0, %rbx t_init_end: t_exit: mov $60, %rax syscall t_exit_end: t_move_head_right: inc %rbx t_move_head_right_end: t_move_head_left: dec %rbx t_move_head_left_end: t_increase_cell: incb (%rbx) t_increase_cell_end: t_decrease_cell: decb (%rbx) t_decrease_cell_end: t_write_cell: mov $1, %rax mov $1, %rdi mov %rbx, %rsi mov $1, %rdx syscall t_write_cell_end: t_read_cell: mov $0, %rax mov $0, %rdi mov %rbx, %rsi mov $1, %rdx syscall t_read_cell_end: t_check_zero: mov (%rbx), %rax cmp $0, %rax .byte 0xf, 0x84 # `je` instruction .int 0x0 # relative offset t_check_zero_end: t_jump_back: .byte 0xe9 # `jmp` instruction .int 0x0 # absolute offset t_jump_back_end: .section constants, "a" c_elf_header: .byte 0x7f # Magic Number .ascii "ELF" # .byte 0x2 # 64-Bit .byte 0x1 # little-endian .byte 0x1 # ELFv1 .byte 0x0 # System V ABI .quad 0x0 # .hword 0x02 # Executable .hword 0x3e # AMD x86-64 .int 0x1 # ELFv1 .quad 0x4005b0 # Entry .quad 0x40 # Program Header Offset .quad 0xb0 # TODO: Section Header Offset .int 0x0 # .hword 0x40 # ELF Header Size .hword 0x38 # Program Header Table Entry Size .hword 0x2 # TODO: Number Of Entries in Program Header Table .hword 0x40 # Section Header Table Entry Size .hword 0x3 # TODO: Number Of Entries in Section Header Table .hword 0x2 # TODO: Index of Section Header Table Entry containing section names c_elf_data_program_header: .int 0x1 # Loadable .int 0x6 # Read Write .quad 0x1b0 # Offset in ELF .quad 0x3001b0 # Virtual Address .quad 0x3001b0 # Physical Address .quad 0x400 # Virtual Size .quad 0x400 # Size in file .quad 0x1000 # Aligning c_elf_data_section_header: .int 0x1 # Index of name in SHSTRTAB .int 0x1 # Load as Program data .quad 0x3 # Is Writable and Readable .quad 0x3001b0 # Virtual Address .quad 0x1b0 # Offset in ELF .quad 0x400 # Size .int 0x0 # Index .int 0x0 # Info .quad 0x1000 # Aligning .quad 0x0 c_elf_shstrtab_section_header: .int 0xb # Index of name in SHSTRTAB .int 0x3 # Don't load .quad 0x0 # No Attributes .quad 0x0 # Not mapped to virtual memory .quad 0x170 # Offset in ELF .quad 0x40 # Size in ELF .int 0x0 # Index .int 0x0 # No Inof .quad 0x1 # Aligning .quad 0x0 c_elf_shstrtab: .byte 0 .asciz "data" .asciz "code" .asciz "shstrtab" c_elf_data: .fill 0x400, 1, 0 c_usage_message: .asciz "bfc [input file] [output file]\n" .section variables, "aw" c_elf_code_program_header: .int 0x1 # Loadable .int 0x5 # Read Executable .quad 0x5b0 # Offset in ELF .quad 0x4005b0 # Virtual Address .quad 0x4005b0 # Physical Address v_elf_code_program_header_file_size: .quad 0x0 # File Size v_elf_code_program_header_memory_size: .quad 0x0 # Memory Size .quad 0x1000 # Aligning c_elf_code_section_header: .int 0x6 # Index of name in SHSTRTAB .int 0x1 # Load as program data .quad 0x6 # Is Readable and Executable .quad 0x4005b0 # Virtual Address .quad 0x5b0 # Offset in ELF v_elf_code_section_header_size: .quad 0x0 .int 0x0 # Index .int 0x0 # Info .quad 0x1000 # Aligning .quad 0x0 v_input_fd: .int 0x0 v_output_fd: .int 0x0 v_buffer_start: .quad 0x0 v_buffer_end: .quad 0x0 v_buffer_cursor: .quad 0x0 v_input_char: .byte 0x0 .section code, "ax" .global _start _start: mov %rsp, %rbp call f_check_args call f_open_files call f_init_buffer mov $t_init, %rdi mov $t_init_end, %rsi call f_write_to_buffer l_read_loop: call f_read_next_character cmp $0, %rax je l_read_loop_end mov $v_input_char, %rbx mov (%rbx), %al cmp $'<', %al je l_compile_move_left cmp $'>', %al je l_compile_move_right cmp $'+', %al je l_compile_inc cmp $'-', %al je l_compile_dec cmp $'[', %al je l_compile_loop_start cmp $']', %al je l_compile_loop_end cmp $'.', %al je l_compile_write cmp $',', %al je l_compile_read jmp l_read_loop l_compile_move_left: mov $t_move_head_left, %rdi mov $t_move_head_left_end, %rsi call f_write_to_buffer jmp l_read_loop l_compile_move_right: mov $t_move_head_right, %rdi mov $t_move_head_right_end, %rsi call f_write_to_buffer jmp l_read_loop l_compile_inc: mov $t_increase_cell, %rdi mov $t_increase_cell_end, %rsi call f_write_to_buffer jmp l_read_loop l_compile_dec: mov $t_decrease_cell, %rdi mov $t_decrease_cell_end, %rsi call f_write_to_buffer jmp l_read_loop l_compile_loop_start: mov $v_buffer_cursor, %rbx push (%rbx) mov $t_check_zero, %rdi mov $t_check_zero_end, %rsi call f_write_to_buffer jmp l_read_loop l_compile_loop_end: pop %r15 mov $t_jump_back, %rdi mov $t_jump_back_end, %rsi call f_write_to_buffer mov $v_buffer_cursor, %rbx mov (%rbx), %rax mov %r15, %rbx sub %rax, %r15 mov %r15d, -4(%rax) neg %r15 sub $13, %r15 mov %r15d, 9(%rbx) jmp l_read_loop l_compile_write: mov $t_write_cell, %rdi mov $t_write_cell_end, %rsi call f_write_to_buffer jmp l_read_loop l_compile_read: mov $t_read_cell, %rdi mov $t_read_cell_end, %rsi call f_write_to_buffer jmp l_read_loop l_read_loop_end: mov $t_exit, %rdi mov $t_exit_end, %rsi call f_write_to_buffer mov $v_buffer_cursor, %rbx mov (%rbx), %rax mov $v_buffer_start, %rbx mov (%rbx), %rbx sub %rbx, %rax mov %rax, %r12 mov $v_elf_code_program_header_file_size, %rbx mov %rax, (%rbx) mov $v_elf_code_program_header_memory_size, %rbx mov %rax, (%rbx) mov $v_elf_code_section_header_size, %rbx mov %rax, (%rbx) mov $c_elf_header, %rsi mov $0x40, %rdx call f_write_to_output mov $c_elf_data_program_header, %rsi mov $0x38, %rdx call f_write_to_output mov $c_elf_code_program_header, %rsi mov $0x38, %rdx call f_write_to_output mov $c_elf_data_section_header, %rsi mov $0x40, %rdx call f_write_to_output mov $c_elf_code_section_header, %rsi mov $0x40, %rdx call f_write_to_output mov $c_elf_shstrtab_section_header, %rsi mov $0x40, %rdx call f_write_to_output mov $c_elf_shstrtab, %rsi mov $0x40, %rdx call f_write_to_output mov $c_elf_data, %rsi mov $0x400, %rdx call f_write_to_output mov $v_buffer_start, %rbx mov (%rbx), %rsi mov %r12, %rdx call f_write_to_output call f_close_files mov $0, %rdi jmp f_exit f_exit: mov $SYS_EXIT, %rax syscall /* rsi = buffer, %rdx = len */ f_write_to_output: mov $SYS_WRITE, %rax mov $v_output_fd, %rbx mov (%rbx), %rdi syscall ret /* rdi = buffer, %rsi = buffer end */ f_write_to_buffer: sub %rdi, %rsi mov %rsi, %r12 mov %rdi, %r13 mov $v_buffer_cursor, %rbx mov (%rbx), %rax add %rax, %rsi call f_check_buffer mov $v_buffer_cursor, %rbx mov (%rbx), %rax l_write_loop_start: cmp $0, %r12 je l_write_loop_end mov (%r13), %sil mov %sil, (%rax) inc %r13 inc %rax dec %r12 jmp l_write_loop_start l_write_loop_end: mov %rax, (%rbx) ret f_check_args: mov (%rbp), %rax cmp $3, %rax je l_check_args_success mov $SYS_WRITE, %rax mov $2, %rdi mov $c_usage_message, %rsi mov $32, %rdx syscall mov $-1, %rdi jmp f_exit l_check_args_success: ret f_open_files: mov $SYS_OPEN, %rax mov 16(%rbp), %rdi mov $0, %rsi mov $0, %rdx syscall mov $v_input_fd, %rbx mov %eax, (%rbx) mov $SYS_OPEN, %rax mov 24(%rbp), %rdi mov $F_CREATE_AND_WRITE, %rsi mov $F_MODE_EXECUTABLE, %rdx syscall mov $v_output_fd, %rbx mov %eax, (%rbx) mov %eax, %edi mov $0, %rsi mov $77, %rax syscall ret f_close_files: mov $SYS_CLOSE, %rax mov %rbx, %rsi syscall mov $SYS_CLOSE, %rax mov %rcx, %rsi syscall ret f_init_buffer: mov $SYS_BRK, %rax mov $0, %rdi syscall mov $v_buffer_start, %rbx mov %rax, (%rbx) mov $v_buffer_end, %rbx mov %rax, (%rbx) mov $v_buffer_cursor, %rbx mov %rax, (%rbx) jmp f_resize_buffer /* * We directly skip to f_resize_buffer * since we want to resize it to a usable amount */ f_resize_buffer: mov $SYS_BRK, %rax mov $v_buffer_end, %rbx mov (%rbx), %rdi add $0x400, %rdi syscall mov %rax, (%rbx) ret /* %rsi = needed end */ f_check_buffer: mov $v_buffer_end, %rbx mov (%rbx), %rax cmp %rax, %rsi jl l_check_buffer_large_enough call f_resize_buffer l_check_buffer_large_enough: ret f_read_next_character: mov $SYS_READ, %rax mov $v_input_fd, %rbx mov (%rbx), %rdi mov $v_input_char, %rsi mov $1, %rdx syscall ret