match ,{ include 'ccall.inc' include 'struct.inc' } match -,{ else include 'selfhost.inc' end match _ equ } format ELF public main include '../version.inc' extrn 'malloc' as libc.malloc extrn 'realloc' as libc.realloc extrn 'free' as libc.free extrn 'fopen' as libc.fopen extrn 'fclose' as libc.fclose extrn 'fread' as libc.fread extrn 'fwrite' as libc.fwrite extrn 'fseek' as libc.fseek extrn 'ftell' as libc.ftell extrn 'time' as libc.time extrn 'write' as libc.write extrn getenv extrn gettimeofday extrn exit struct timeval time_t dd ? suseconds_t dd ? ends section '.text' executable align 16 main: mov ecx,[esp+4] mov [argc],ecx mov ebx,[esp+8] mov [argv],ebx call system_init call get_arguments mov bl,al cmp [no_logo],0 jne logo_ok mov esi,_logo xor ecx,ecx call display_string logo_ok: test bl,bl jnz display_usage_information xor al,al mov ecx,[verbosity_level] jecxz init or al,TRACE_ERROR_STACK dec ecx jz init or al,TRACE_DISPLAY init: call assembly_init ccall gettimeofday,start_time,0 assemble: mov esi,[initial_commands] mov edx,[source_path] call assembly_pass jc assembly_done mov eax,[current_pass] cmp eax,[maximum_number_of_passes] jb assemble call show_display_data mov esi,_error_prefix xor ecx,ecx call display_error_string mov esi,_code_cannot_be_generated xor ecx,ecx call display_error_string mov esi,_message_suffix xor ecx,ecx call display_error_string jmp assembly_failed assembly_done: call show_display_data cmp [first_error],0 jne assembly_failed cmp [no_logo],0 jne summary_done mov eax,[current_pass] xor edx,edx call itoa call display_string mov esi,_passes cmp [current_pass],1 jne display_passes_suffix mov esi,_pass display_passes_suffix: xor ecx,ecx call display_string ccall gettimeofday,end_time,0 mov eax,[end_time.time_t] sub eax,[start_time.time_t] mov ecx,1000000 mul ecx add eax,[end_time.suseconds_t] adc edx,0 sub eax,[start_time.suseconds_t] sbb edx,0 add eax,50000 mov ecx,1000000 div ecx mov ebx,eax mov eax,edx xor edx,edx mov ecx,100000 div ecx mov [tenths_of_second],eax xchg eax,ebx or ebx,eax jz display_output_length xor edx,edx call itoa call display_string mov esi,_message_suffix mov ecx,1 call display_string mov eax,[tenths_of_second] xor edx,edx call itoa call display_string mov esi,_seconds xor ecx,ecx call display_string display_output_length: call get_output_length push eax edx call itoa call display_string pop edx eax mov esi,_bytes cmp eax,1 jne display_bytes_suffix test edx,edx jnz display_bytes_suffix mov esi,_byte display_bytes_suffix: xor ecx,ecx call display_string mov esi,_new_line xor ecx,ecx call display_string summary_done: mov ebx,[source_path] mov edi,[output_path] call write_output_file jc write_failed call assembly_shutdown call system_shutdown ccall exit,0 assembly_failed: call show_errors call assembly_shutdown call system_shutdown ccall exit,2 write_failed: mov ebx,_write_failed jmp fatal_error out_of_memory: mov ebx,_out_of_memory jmp fatal_error fatal_error: mov esi,_error_prefix xor ecx,ecx call display_error_string mov esi,ebx xor ecx,ecx call display_error_string mov esi,_message_suffix xor ecx,ecx call display_error_string call assembly_shutdown call system_shutdown ccall exit,3 display_usage_information: mov esi,_usage xor ecx,ecx call display_string call system_shutdown ccall exit,1 get_arguments: xor eax,eax mov [initial_commands],eax mov [source_path],eax mov [output_path],eax mov [no_logo],al mov [verbosity_level],eax mov [maximum_number_of_passes],100 mov [maximum_number_of_errors],1 mov [maximum_depth_of_stack],10000 mov ecx,[argc] mov ebx,[argv] add ebx,4 dec ecx jz error_in_arguments get_argument: mov esi,[ebx] mov al,[esi] cmp al,'-' je get_option cmp [source_path],0 jne get_output_file mov [source_path],esi jmp next_argument get_output_file: cmp [output_path],0 jne error_in_arguments mov [output_path],esi jmp next_argument get_option: inc esi lodsb cmp al,'e' je set_errors_limit cmp al,'E' je set_errors_limit cmp al,'i' je insert_initial_command cmp al,'I' je insert_initial_command cmp al,'p' je set_passes_limit cmp al,'P' je set_passes_limit cmp al,'r' je set_recursion_limit cmp al,'R' je set_recursion_limit cmp al,'v' je set_verbose_mode cmp al,'V' je set_verbose_mode cmp al,'n' je set_no_logo cmp al,'N' jne error_in_arguments set_no_logo: or [no_logo],-1 cmp byte [esi],0 je next_argument error_in_arguments: or al,-1 ret set_verbose_mode: cmp byte [esi],0 jne get_verbose_setting dec ecx jz error_in_arguments add ebx,4 mov esi,[ebx] get_verbose_setting: call get_option_value cmp edx,2 ja error_in_arguments mov [verbosity_level],edx jmp next_argument set_errors_limit: cmp byte [esi],0 jne get_errors_setting dec ecx jz error_in_arguments add ebx,4 mov esi,[ebx] get_errors_setting: call get_option_value test edx,edx jz error_in_arguments mov [maximum_number_of_errors],edx jmp next_argument set_recursion_limit: cmp byte [esi],0 jne get_recursion_setting dec ecx jz error_in_arguments add ebx,4 mov esi,[ebx] get_recursion_setting: call get_option_value test edx,edx jz error_in_arguments mov [maximum_depth_of_stack],edx jmp next_argument set_passes_limit: cmp byte [esi],0 jne get_passes_setting dec ecx jz error_in_arguments add ebx,4 mov esi,[ebx] get_passes_setting: call get_option_value test edx,edx jz error_in_arguments mov [maximum_number_of_passes],edx next_argument: add ebx,4 dec ecx jnz get_argument cmp [source_path],0 je error_in_arguments xor al,al ret get_option_value: xor eax,eax mov edx,eax find_option_value: cmp byte [esi],20h jne get_option_digit inc esi jmp find_option_value get_option_digit: lodsb test al,al jz option_value_ok sub al,30h jc invalid_option_value cmp al,9 ja invalid_option_value imul edx,10 jo invalid_option_value add edx,eax jc invalid_option_value jmp get_option_digit option_value_ok: dec esi clc ret invalid_option_value: stc ret insert_initial_command: cmp byte [esi],0 jne measure_initial_command dec ecx jz error_in_arguments add ebx,4 mov esi,[ebx] measure_initial_command: push ebx ecx edi mov edi,esi or ecx,-1 xor al,al repne scasb not ecx dec ecx mov edi,[initial_commands] lea eax,[ecx+2] test edi,edi jz allocate_initial_commands_buffer mov edx,[initial_commands_length] add edi,edx add eax,edx cmp eax,[initial_commands_maximum_length] ja grow_initial_commands_buffer copy_initial_command: rep movsb mov ax,0Ah stosw dec edi sub edi,[initial_commands] mov [initial_commands_length],edi pop edi ecx ebx jmp next_argument allocate_initial_commands_buffer: push ecx mov ecx,eax call malloc mov [initial_commands],eax mov [initial_commands_maximum_length],ecx mov edi,eax pop ecx jmp copy_initial_command grow_initial_commands_buffer: push ecx mov ecx,eax mov eax,[initial_commands] call realloc mov [initial_commands],eax mov [initial_commands_maximum_length],ecx mov edi,eax add edi,[initial_commands_length] pop ecx jmp copy_initial_command include 'system.inc' include '../assembler.inc' include '../symbols.inc' include '../expressions.inc' include '../conditions.inc' include '../floats.inc' include '../directives.inc' include '../calm.inc' include '../errors.inc' include '../map.inc' include '../reader.inc' include '../output.inc' include '../console.inc' section '.data' _logo db 'flat assembler version g.',VERSION,10,0 _usage db 'Usage: fasmg source [output]',10 db 'Optional settings:',10 db ' -p limit Set the maximum allowed number of passes (default 100)',10 db ' -e limit Set the maximum number of displayed errors (default 1)',10 db ' -r limit Set the maximum depth of the stack (default 10000)',10 db ' -v flag Enable or disable showing all lines from the stack (default 0)',10 db ' -i command Insert instruction at the beginning of source',13,10 db ' -n Do not show logo nor summary',13,10 db 0 _pass db ' pass, ',0 _passes db ' passes, ',0 _dot db '.' _seconds db ' seconds, ',0 _byte db ' byte.',0 _bytes db ' bytes.',0 _write_failed db 'failed to write the output file',0 _out_of_memory db 'not enough memory to complete the assembly',0 _code_cannot_be_generated db 'could not generate code within the allowed number of passes',0 _open_mode db 'r',0 _create_mode db 'w',0 include '../tables.inc' include '../messages.inc' section '.bss' writeable align 4 include '../variables.inc' source_path dd ? output_path dd ? maximum_number_of_passes dd ? initial_commands dd ? initial_commands_length dd ? initial_commands_maximum_length dd ? argc dd ? argv dd ? timestamp dq ? start_time timeval end_time timeval tenths_of_second dd ? verbosity_level dd ? no_logo db ? path_buffer rb 1000h