.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 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 l_read_loop: call f_read_next_character cmp $0, %rax je l_read_loop_end mov $v_input_char, %rbx mov (%rbx), %rax cmp $'<', %rax je l_compile_move_left cmp $'>', %rax je l_compile_move_right cmp $'+', %rax je l_compile_inc cmp $'-', %rax je l_compile_dec cmp $'[', %rax je l_compile_loop_start cmp $']', %rax je l_compile_loop_end cmp $'.', %rax je l_compile_write cmp $',', %rax je l_compile_read jmp l_read_loop l_compile_move_left: # TODO: fix buffer overflows mov $v_buffer_cursor, %rbx mov (%rbx), %rsi add $3, %rsi call f_check_buffer mov $v_buffer_cursor, %rbx mov (%rbx), %rax movl $0xc0ff48, (%rax) add $3, %rax mov %rax, (%rbx) jmp l_read_loop l_compile_move_right: # TODO: fix buffer overflows mov $v_buffer_cursor, %rbx mov (%rbx), %rsi add $3, %rsi call f_check_buffer mov $v_buffer_cursor, %rbx mov (%rbx), %rax movl $0xc8ff48, (%rax) add $3, %rax mov %rax, (%rbx) jmp l_read_loop l_compile_inc: jmp l_read_loop l_compile_dec: jmp l_read_loop l_compile_loop_start: jmp l_read_loop l_compile_loop_end: jmp l_read_loop l_compile_write: jmp l_read_loop l_compile_read: jmp l_read_loop l_read_loop_end: mov $v_buffer_cursor, %rbx mov (%rbx), %rax movl $0x3cc0c748, (%rax) add $7, %rax movl $0x050f, (%rax) add $2, %rax mov %rax, (%rbx) 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 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) 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) /* * 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