add flat assembler toolchain

This commit is contained in:
2024-11-24 23:13:28 -05:00
parent 99e8e4072b
commit dbfd94ea40
302 changed files with 145599 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,669 @@
COND_NEGATED = 1 ; only with COND_EVALUATE
COND_TRUE = 1 ; only with COND_DETERMINED
COND_EVALUATE = 2
COND_DETERMINED = 4
get_condition_value:
; in:
; esi = pointer into preprocessed line or the last embedded line
; out:
; esi = pointer advanced past the processed line
; al = logical value
mov ebx,[condition_stack_base]
mov [condition_stack],ebx
mov byte [ebx],COND_EVALUATE
get_logical_value:
call peek_at_constituent_value
cmp al,'~'
jne negation_registered
and [current_constituent],0
mov ebx,[condition_stack]
mov al,[ebx]
test byte [ebx],COND_EVALUATE
jz get_logical_value
xor byte [ebx],COND_NEGATED
jmp get_logical_value
negation_registered:
call parse_logical_value
setnc dh
mov dl,al
jecxz get_logical_operator
mov ebx,[condition_stack]
lea eax,[ebx+ecx+1]
cmp eax,[condition_stack_end]
jbe condition_stack_ready
push ecx edx
mov ecx,eax
mov eax,[condition_stack_base]
sub ecx,eax
sub ebx,eax
call grow_stack
mov [condition_stack_base],eax
add ebx,eax
mov [condition_stack],ebx
add eax,ecx
mov [condition_stack_end],eax
pop edx ecx
condition_stack_ready:
xor al,al
test byte [ebx],COND_EVALUATE
jz store_opening_parentheses
or al,COND_EVALUATE
store_opening_parentheses:
inc ebx
mov [ebx],al
loop store_opening_parentheses
mov [condition_stack],ebx
cmp dx,'~'
je get_logical_value
get_logical_operator:
call peek_at_constituent_value
jc end_of_logical_expression
cmp al,')'
je close_logical_subexpression
cmp al,'|'
je logical_or
cmp al,'&'
jne end_of_logical_expression
logical_and:
and [current_constituent],0
mov ebx,[condition_stack]
mov al,[ebx]
test al,COND_EVALUATE
jnz evaluate_logical_and
test al,COND_DETERMINED
jz get_logical_value
test al,COND_TRUE
jz determined_false
jmp continue_evaluation
evaluate_logical_and:
test al,COND_NEGATED
jnz evaluate_negated_logical_and
call evaluate_logical_value
mov ebx,[condition_stack]
test al,al
jnz continue_evaluation
determined_false:
mov byte [ebx],COND_DETERMINED
jmp get_logical_value
evaluate_negated_logical_and:
call evaluate_logical_value
mov ebx,[condition_stack]
test al,al
jnz determined_false
continue_evaluation:
mov byte [ebx],COND_EVALUATE
jmp get_logical_value
logical_or:
and [current_constituent],0
mov ebx,[condition_stack]
mov al,[ebx]
test al,COND_EVALUATE
jnz evaluate_logical_or
test al,COND_DETERMINED
jz get_logical_value
test al,COND_TRUE
jnz determined_true
jmp continue_evaluation
evaluate_logical_or:
test al,COND_NEGATED
jnz evaluate_negated_logical_or
call evaluate_logical_value
mov ebx,[condition_stack]
test al,al
jnz determined_true
jmp continue_evaluation
evaluate_negated_logical_or:
call evaluate_logical_value
mov ebx,[condition_stack]
test al,al
jnz continue_evaluation
determined_true:
mov byte [ebx],COND_DETERMINED + COND_TRUE
jmp get_logical_value
close_logical_subexpression:
and [current_constituent],0
mov ebx,[condition_stack]
cmp ebx,[condition_stack_base]
je excess_parenthesis
mov al,[ebx]
dec ebx
mov [condition_stack],ebx
test al,COND_DETERMINED
jnz subexpression_determined
cmp al,COND_EVALUATE + COND_NEGATED
jne get_logical_operator
test byte [ebx],COND_EVALUATE
jz get_logical_operator
xor byte [ebx],COND_NEGATED
jmp get_logical_operator
subexpression_determined:
test al,COND_TRUE
jnz subexpression_determined_true
mov [comparator],evaluated_false
jmp get_logical_operator
subexpression_determined_true:
mov [comparator],evaluated_true
jmp get_logical_operator
end_of_logical_expression:
mov ebx,[condition_stack]
cmp ebx,[condition_stack_base]
jne missing_parenthesis
mov al,[ebx]
test al,COND_DETERMINED
jnz condition_determined
test al,COND_NEGATED
jz evaluate_logical_value
call evaluate_logical_value
test al,al
setz al
retn
condition_determined:
and al,COND_TRUE
retn
excess_parenthesis:
mov edx,_excess_closing_parenthesis
call register_error
jmp unknown_condition
missing_parenthesis:
mov edx,_missing_closing_parenthesis
call register_error
unknown_condition:
xor al,al
retn
parse_logical_value:
; in:
; esi = pointer into preprocessed line or the last embedded line
; out:
; [comparator] - evaluating routine
; [expression_workspace.memory_start] - parsed argument sequences
; [expression_end] - end of the parsed argument sequences
; esi = pointer advanced past the parsed value
; al = special character that follows parsed value, zero if no more symbols in line
; ecx = number of parentheses opened before the value that did not get closed
; cf set if value was empty
mov edi,[expression_workspace.memory_start]
xor eax,eax
mov [comparator],eax
or [leave_opening_parentheses],1
call parse_expression
mov [initial_parentheses],ecx
mov [expression_end],edi
call peek_at_constituent_value
jc end_of_line
cmp al,'&'
je end_of_logical_value
cmp al,'|'
je end_of_logical_value
cmp al,'~'
je end_of_logical_value
cmp al,')'
je end_of_logical_value
cmp al,1Ah
je identify_comparator
cmp al,'='
je parse_equal
cmp al,'<'
je parse_less
cmp al,'>'
je parse_greater
jmp end_of_logical_value
identify_comparator:
test edx,edx
jz end_of_logical_value
cmp [edx+ValueDefinition.type],VALTYPE_NATIVE_COMPARATOR
jne end_of_logical_value
and [current_constituent],0
mov eax,[edx+ValueDefinition.value]
jmp set_comparator
parse_less:
and [current_constituent],0
call warp_to_next_symbol
jc parse_less_than
test ecx,ecx
jnz parse_less_than
call peek_at_constituent_value
jc parse_less_than
cmp al,'='
je parse_less_or_equal
cmp al,'>'
je parse_not_equal
parse_less_than:
mov eax,check_if_less
jmp set_comparator
parse_less_or_equal:
and [current_constituent],0
mov eax,check_if_not_greater
jmp set_comparator
parse_not_equal:
and [current_constituent],0
mov eax,check_if_not_equal
jmp set_comparator
parse_greater:
and [current_constituent],0
call warp_to_next_symbol
jc parse_greater_than
test ecx,ecx
jnz parse_greater_than
call peek_at_constituent_value
jc parse_greater_than
cmp al,'='
je parse_greater_or_equal
parse_greater_than:
mov eax,check_if_greater
jmp set_comparator
parse_greater_or_equal:
and [current_constituent],0
mov eax,check_if_not_less
jmp set_comparator
parse_equal:
and [current_constituent],0
mov eax,check_if_equal
set_comparator:
mov edi,[expression_end]
mov [comparator],eax
and [leave_opening_parentheses],0
call parse_expression
mov [expression_end],edi
call peek_at_constituent_value
jnc end_of_logical_value
end_of_line:
xor al,al
end_of_logical_value:
mov ecx,[initial_parentheses]
cmp [comparator],0
jnz logical_value_not_empty
mov [comparator],check_if_not_zero
mov ebx,[expression_workspace.memory_start]
cmp dword [ebx],0
jne logical_value_not_empty
stc
retn
logical_value_not_empty:
clc
retn
evaluate_logical_value:
; in:
; [comparator] - evaluating routine
; [expression_workspace.memory_start] - parsed argument sequences
; out: al = logical value
; note: evaluates value prepared by previous call to parse_logical_value
; preserves: esi
push esi
mov esi,[expression_workspace.memory_start]
jmp [comparator]
evaluated_false:
pop esi
xor al,al
retn
evaluated_true:
pop esi
mov al,1
retn
evaluate_stored_logical_value:
; in: esi - pointer to evaluating routine followed by parsed argument sequences
; out: al = logical value
; preserves: esi
push esi
lodsd
jmp eax
invalid_logical_value:
mov edx,_invalid_expression
call register_error
jmp evaluated_false
check_if_equal:
call get_difference_signum
test al,al
jz evaluated_true
jmp evaluated_false
check_if_not_equal:
call get_difference_signum
test al,al
jnz evaluated_true
jmp evaluated_false
check_if_less:
call get_difference_signum
cmp al,0
jl evaluated_true
jmp evaluated_false
check_if_not_less:
call get_difference_signum
cmp al,0
jnl evaluated_true
jmp evaluated_false
check_if_greater:
call get_difference_signum
cmp al,0
jg evaluated_true
jmp evaluated_false
check_if_not_greater:
call get_difference_signum
cmp al,0
jng evaluated_true
jmp evaluated_false
get_difference_signum:
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
jc signum_error
call calculate_parsed_expression
jc signum_error
mov esi,subtraction_operator
call calculate_parsed_expression
call pop_terms
mov eax,edi
jnc check_difference_for_variable_terms
signum_error:
xor al,al
retn
check_difference_for_variable_terms:
add eax,sizeof.ExpressionTerm
cmp [eax+ExpressionTerm.attributes],0
je difference_terms_ok
cmp [eax+ExpressionTerm.metadata],0
je check_difference_for_variable_terms
mov edx,_values_not_comparable
call register_error
difference_terms_ok:
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je get_float_signum
call get_numeric_term_value
mov ecx,1
call fit_value
js signum_negative
jc signum_positive
xor al,al
cmp [edi],al
jne signum_positive
retn
get_float_signum:
call get_term_value
mov esi,edx
call get_float_exponent
jz signum_zero
test [esi+FloatData.attributes],FLOAT_NEGATIVE
jnz signum_negative
signum_positive:
mov al,1
retn
signum_negative:
or al,-1
retn
signum_zero:
xor al,al
retn
check_if_not_zero:
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
jc evaluated_false
call pop_terms
jc evaluated_false
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je check_if_not_zero_float
call get_numeric_term_value
mov ecx,1
call fit_value
js evaluated_true
jc evaluated_true
cmp byte [edi],0
jne evaluated_true
check_if_has_variable_terms:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je evaluated_false
cmp [edi+ExpressionTerm.metadata],0
je check_if_has_variable_terms
jmp evaluated_true
check_if_not_zero_float:
call get_term_value
mov esi,edx
call get_float_exponent
jz check_if_has_variable_terms
jmp evaluated_true
check_if_relative:
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
jc evaluated_false
call calculate_parsed_expression
jc evaluated_false
mov ebx,edi
call pop_terms
jc evaluated_false
mov edx,edi
call pop_terms
jc evaluated_false
cmp [edx+sizeof.ExpressionTerm+ExpressionTerm.attributes],0
je check_difference_terms
xchg edi,edx
cmp [edx+sizeof.ExpressionTerm+ExpressionTerm.attributes],0
je check_difference_terms
mov esi,subtraction_operator
mov edi,ebx
call calculate_parsed_expression
call pop_terms
jc evaluated_false
check_difference_terms:
add edi,sizeof.ExpressionTerm
cmp [edi+ExpressionTerm.attributes],0
je evaluated_true
cmp [edi+ExpressionTerm.metadata],0
je check_difference_terms
jmp evaluated_false
undefined_condition:
mov edx,_invalid_value
call register_error
jmp evaluated_false
check_if_type_equal:
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
jc evaluated_false
call pop_terms
jc evaluated_false
mov eax,[edi+ExpressionTerm.attributes]
mov [result_type],al
call calculate_parsed_expression
jc evaluated_false
call pop_terms
jc evaluated_false
mov eax,[edi+ExpressionTerm.attributes]
cmp al,[result_type]
je evaluated_true
jmp evaluated_false
check_if_value_equal:
mov edi,[calculation_workspace.memory_start]
call calculate_parsed_expression
jc evaluated_false
mov ebx,edi
call pop_terms
jc evaluated_false
mov eax,[edi+ExpressionTerm.attributes]
mov [result_type],al
mov edi,ebx
call calculate_parsed_expression
jc evaluated_false
mov ebx,edi
call pop_terms
jc evaluated_false
mov eax,[edi+ExpressionTerm.attributes]
cmp al,[result_type]
jne evaluated_false
cmp al,EXPR_STRING
jne compare_values_numerically
call get_term_value
mov ecx,[edx]
call pop_terms
call get_term_value
cmp ecx,[edx]
jne evaluated_false
compare_values_numerically:
mov esi,subtraction_operator
mov edi,ebx
call calculate_parsed_expression
call pop_terms
jc evaluated_false
mov eax,edi
check_if_terms_equal:
add eax,sizeof.ExpressionTerm
cmp [eax+ExpressionTerm.attributes],0
je check_if_constant_term_equal
cmp [eax+ExpressionTerm.metadata],0
je check_if_terms_equal
jmp evaluated_false
check_if_constant_term_equal:
cmp byte [edi+ExpressionTerm.attributes],EXPR_FLOAT
je check_if_float_equal
call get_numeric_term_value
xor ecx,ecx
xor edi,edi
call fit_value
jc evaluated_false
jmp evaluated_true
check_if_float_equal:
call get_term_value
mov esi,edx
call get_float_exponent
jnz evaluated_false
jmp evaluated_true
check_if_defined:
xor ecx,ecx
jmp check_if_expression_defined
check_if_defined_earlier:
mov ecx,[current_pass]
check_if_expression_defined:
and [outer_expression],0
and [defined_element],0
lodsd
test eax,eax
jnz checked_expression_invalid
check_expression_element:
lodsd
test eax,eax
jz check_expression_end
cmp al,EXPR_SYMBOL
je check_if_subexpression_defined
cmp al,EXPR_SYMBOL_VALUE
je check_if_symbol_defined
or [defined_element],1
add esi,4
cmp al,EXPR_NUMBER
je check_expression_element
cmp al,EXPR_STRING
je check_expression_element
cmp al,EXPR_FLOAT
je check_expression_element
cmp al,EXPR_OPERATOR
je check_expression_element
cmp al,EXPR_POLYNOMIAL
je check_expression_element
checked_expression_invalid:
jmp invalid_logical_value
check_expression_end:
xor esi,esi
xchg esi,[outer_expression]
test esi,esi
jnz check_expression_element
jecxz checked_expression_defined
cmp [defined_element],0
je checked_expression_invalid
checked_expression_defined:
jmp evaluated_true
check_if_symbol_defined:
lodsd
test eax,eax
jz evaluated_false
lodsd
test eax,eax
jz evaluated_false
check_symbol_value:
or [defined_element],1
jecxz check_expression_element
test [eax+ValueDefinition.flags],VAL_INTERNAL
jnz check_expression_element
cmp [eax+ValueDefinition.pass],ecx
jne evaluated_false
jmp check_expression_element
check_if_subexpression_defined:
mov ebx,[esi]
test ebx,ebx
jz evaluated_false
add esi,4
call get_available_value
mov eax,edx
test eax,eax
jz evaluated_false
cmp [eax+ValueDefinition.type],VALTYPE_SYMBOLIC
jne check_symbol_value
mov [outer_expression],esi
push ecx
call get_subexpression
pop ecx
jnc invalid_logical_value
jmp check_expression_element
get_subexpression:
call clear_line_embeddings
xor esi,esi
xor ecx,ecx
call embed_symbolic_value
mov edi,[expression_workspace.memory_start]
and [leave_opening_parentheses],0
call parse_expression
call get_constituent_value
mov esi,[expression_workspace.memory_start]
retn
check_if_used:
lodsd
test eax,eax
jnz invalid_logical_value
check_if_expression_is_used_symbol:
lodsd
cmp al,EXPR_SYMBOL
je check_for_indirect_symbol
cmp al,EXPR_SYMBOL_VALUE
jne invalid_logical_value
lodsd
mov ebx,eax
lodsd
check_if_used_symbol:
lodsd
test eax,eax
jnz invalid_logical_value
test ebx,ebx
jz evaluated_false
mov ecx,[ebx+SymbolTree_Leaf.last_use_pass]
jecxz symbol_predicted_unused
mov eax,[current_pass]
sub eax,ecx
jz evaluated_true
cmp eax,1
ja symbol_predicted_unused
symbol_predicted_used:
or [ebx+SymbolTree_Leaf.flags],SYM_USAGE_PREDICTED + SYM_PREDICTED_USED
jmp evaluated_true
symbol_predicted_unused:
mov al,[ebx+SymbolTree_Leaf.flags]
or al,SYM_USAGE_PREDICTED
and al,not SYM_PREDICTED_USED
mov [ebx+SymbolTree_Leaf.flags],al
jmp evaluated_false
check_for_indirect_symbol:
lodsd
mov ebx,eax
call get_available_value
test edx,edx
jz check_if_used_symbol
cmp [edx+ValueDefinition.type],VALTYPE_SYMBOLIC
jne check_if_used_symbol
call get_subexpression
jnc invalid_logical_value
jmp check_if_expression_is_used_symbol

View File

@ -0,0 +1,560 @@
display_string_data:
; in:
; edx - 32-bit length followed by string data
; preserves: esi
test [trace_mode],TRACE_DISPLAY
jnz bypass_display_buffer
cmp [next_pass_needed],0
jne display_ok
mov ecx,[edx]
call reserve_display_buffer
mov ebx,esi
mov esi,edx
lodsd
mov ecx,eax
rep movsb
string_displayed:
mov esi,ebx
display_ok:
retn
bypass_display_buffer:
mov ebx,esi
mov esi,edx
lodsd
mov ecx,eax
jecxz string_displayed
call display_string
jmp string_displayed
reserve_display_buffer:
mov edi,[display_data_length]
add ecx,edi
add edi,[display_buffer]
mov [display_data_length],ecx
cmp ecx,[display_buffer_length]
jbe display_buffer_reserve_ok
mov eax,[display_buffer]
sub edi,eax
push edx
call grow_stack
pop edx
add edi,eax
mov [display_buffer],eax
mov [display_buffer_length],ecx
display_buffer_reserve_ok:
retn
display_single_byte_data:
; in:
; edx - 32-bit length followed by numeric data
; preserves: esi
test [trace_mode],TRACE_DISPLAY
jnz byte_bypassing_display_buffer
cmp [next_pass_needed],0
jne display_ok
mov ecx,1
call reserve_display_buffer
mov ecx,1
call fit_value
jc byte_out_of_range
retn
byte_bypassing_display_buffer:
mov edi,displayed_byte
mov ecx,1
call fit_value
jc byte_out_of_range
mov ebx,esi
mov esi,edi
mov ecx,1
call display_string
jmp string_displayed
byte_out_of_range:
mov edx,_value_out_of_range
call register_error
retn
show_display_data:
test [trace_mode],TRACE_DISPLAY
jnz display_line_feed
mov ecx,[display_data_length]
jecxz display_data_shown
mov esi,[display_buffer]
call display_string
display_line_feed:
mov esi,_new_line
xor ecx,ecx
call display_string
display_data_shown:
retn
show_errors:
mov esi,[first_error]
display_error:
test esi,esi
jz display_data_shown
push esi
mov eax,[esi+sizeof.Error+SourceContext.number_of_entries]
test eax,eax
jz display_error_message
lea ebx,[esi+sizeof.Error+sizeof.SourceContext]
dec eax
imul eax,sizeof.SourceEntry
lea eax,[ebx+eax]
mov [last_source_entry],eax
test [trace_mode],TRACE_ERROR_STACK
jnz show_source_context
and [last_file_source_entry],0
find_last_file_entry:
cmp [eax+SourceEntry.type],SOURCE_FILE
je last_file_entry_found
cmp eax,ebx
je show_source_context
sub eax,sizeof.SourceEntry
jmp find_last_file_entry
last_file_entry_found:
mov [last_file_source_entry],eax
show_source_context:
push ebx
cmp [ebx+SourceEntry.type],SOURCE_MEMORY
je display_memory_source
cmp [ebx+SourceEntry.type],SOURCE_MACRO
jne display_source_name
mov esi,_macro_source
test [ebx+SourceEntry.flags],SRCF_PREPROCESSED
jz display_source_type
mov esi,_preprocessed_source
display_source_type:
xor ecx,ecx
call display_error_string
display_source_name:
mov esi,[ebx+SourceEntry.name]
test esi,esi
jz unnamed_source
mov ecx,[ebx+SourceEntry.name_length]
cmp ecx,-1
je display_source_symbol
call display_error_string
jmp display_line_number
display_source_symbol:
xchg ebx,esi
call show_symbol_name
mov ebx,esi
jmp display_line_number
unnamed_source:
mov esi,_unnamed_source
xor ecx,ecx
call display_error_string
jmp display_line_number
display_memory_source:
mov esi,_memory_source
xor ecx,ecx
call display_error_string
display_line_number:
mov esi,_line_number_prefix
xor ecx,ecx
call display_error_string
mov eax,[ebx+SourceEntry.line_number]
xor edx,edx
call itoa
call display_error_string
mov esi,_line_number_suffix
xor ecx,ecx
call display_error_string
pop ebx
mov esi,[esp]
push ebx
cmp [ebx+SourceEntry.line_number],0
je skip_line_content
test [trace_mode],TRACE_ERROR_STACK
jnz show_source_line
cmp ebx,[last_source_entry]
je last_source_entry_line_content
cmp ebx,[last_file_source_entry]
je show_source_line
skip_line_content:
mov esi,_space
next_source_entry:
pop ebx
find_next_source_entry:
cmp ebx,[last_source_entry]
je source_context_shown
add ebx,sizeof.SourceEntry
test [trace_mode],TRACE_ERROR_STACK
jnz show_source_entry
test [ebx+SourceEntry.flags],SRCF_PREPROCESSED
jnz find_next_source_entry
show_source_entry:
xor ecx,ecx
call display_error_string
jmp show_source_context
last_source_entry_line_content:
test [esi+Error.flags],ERR_CUSTOM
jnz skip_line_content
show_source_line:
cmp [ebx+SourceEntry.type],SOURCE_CALM
je show_calm_source
mov esi,_line_content_prefix
xor ecx,ecx
call display_error_string
call show_line_content
mov esi,_new_line
jmp next_source_entry
show_calm_source:
mov esi,_calm_source
xor ecx,ecx
call display_error_string
mov esi,_new_line
jmp next_source_entry
source_context_shown:
mov esi,_new_line
xor ecx,ecx
call display_error_string
mov ebx,[esp]
test [ebx+Error.flags],ERR_CUSTOM
jnz display_error_message
cmp [ebx+Error.preprocessed_length],0
je display_error_message
mov esi,_preprocessed_text_prefix
xor ecx,ecx
call display_error_string
mov esi,[ebx+Error.preprocessed_data]
mov ecx,[ebx+Error.preprocessed_length]
call show_preprocessed_line
mov esi,_new_line
xor ecx,ecx
call display_error_string
display_error_message:
pop ebx
call show_error_message
mov esi,ebx
next_error:
mov esi,[esi+Error.next]
jmp display_error
show_error_message:
; in:
; ebx - Error
; preserves: ebx
mov esi,_error_prefix
test [ebx+Error.flags],ERR_CUSTOM
jz display_error_prefix
mov esi,_custom_error_prefix
display_error_prefix:
xor ecx,ecx
call display_error_string
mov esi,[ebx+Error.message]
test [ebx+Error.flags],ERR_CUSTOM
jz format_error_message
xor ecx,ecx
call display_error_string
finish_error_message:
mov esi,_message_suffix
xor ecx,ecx
call display_error_string
retn
format_error_message:
mov edx,esi
cut_error_message:
lodsb
test al,al
jz show_error_message_segment
cmp al,'%'
jne cut_error_message
show_error_message_segment:
dec esi
push esi
xchg ecx,esi
sub ecx,edx
mov esi,edx
call display_error_string
pop esi
lodsb
test al,al
jz finish_error_message
lodsb
cmp al,'s'
je insert_string_into_error_message
cmp al,'i'
jne format_error_message
push ebx
mov ebx,[ebx+Error.symbol]
mov ebx,[ebx+SymbolTree_Leaf.branch]
call show_symbol_name
pop ebx
jmp format_error_message
insert_string_into_error_message:
push esi
mov esi,[ebx+Error.symbol]
xor ecx,ecx
call display_error_string
pop esi
jmp format_error_message
show_symbol_name:
; in:
; ebx - SymbolTree_Foliage, may be null
; preserves: esi
test ebx,ebx
jz symbol_name_shown
mov edi,[identifier_workspace.memory_start]
cmp [ebx+SymbolTree_Foliage.name_kind],NAME_NUMERIC
je next_name_segment
compose_symbol_name:
mov ecx,[ebx+SymbolTree_Foliage.name_length]
mov edx,identifier_workspace
mov al,[ebx+SymbolTree_Foliage.name_kind]
cmp al,NAME_CASESENSITIVE
je name_segment_to_copy
cmp al,NAME_ABSTRACT
je name_segment_copied
cmp al,NAME_NUMERIC
je dot_label_name
mov al,'?'
stosb
name_segment_to_copy:
push ecx
add ecx,2
call reserve_workspace
pop ecx
mov edx,[ebx+SymbolTree_Foliage.name_data]
copy_name_segment:
jecxz name_segment_copied
dec ecx
mov al,[edx+ecx]
stosb
jmp copy_name_segment
dot_label_name:
push esi
mov esi,[ebx+SymbolTree_Foliage.name_data]
xor eax,eax
read_dot_count:
jecxz dot_count_read
dec ecx
shl eax,8
mov al,[esi+ecx]
jmp read_dot_count
dot_count_read:
pop esi
push eax
lea ecx,[eax+2]
call reserve_workspace
pop ecx
mov al,'.'
rep stosb
name_segment_copied:
mov edx,[ebx+SymbolTree_Foliage.root]
mov ebx,[edx+SymbolTree_Root.parent_branch]
test [edx+SymbolTree_Root.flags],NAMESPACE_LOCAL or NAMESPACE_CALM
jnz mark_local_symbol_name
test ebx,ebx
jz symbol_name_ready
next_name_segment:
mov al,'.'
stosb
jmp compose_symbol_name
mark_local_symbol_name:
mov al,':'
stosb
test [edx+SymbolTree_Root.flags],NAMESPACE_CALM
jz symbol_name_ready
mov eax,[ebx+SymbolTree_Foliage.name_data]
mov ebx,[eax+SymbolTree_Leaf.branch]
test ebx,ebx
jnz compose_symbol_name
symbol_name_ready:
mov ebx,[identifier_workspace.memory_start]
mov ecx,edi
sub ecx,ebx
jz symbol_name_shown
push esi
mov esi,ebx
reverse_composed_name:
dec edi
cmp ebx,edi
jae show_composed_name
mov al,[ebx]
xchg al,[edi]
mov [ebx],al
inc ebx
jmp reverse_composed_name
show_composed_name:
call display_error_string
pop esi
symbol_name_shown:
retn
show_line_content:
; in:
; ebx - SourceEntry
cmp [ebx+SourceEntry.type],SOURCE_MACRO
je show_line_from_macro
mov esi,[ebx+SourceEntry.text]
add esi,[ebx+SourceEntry.line_offset]
mov ecx,[ebx+SourceEntry.number_of_attached_lines]
inc ecx
mov [number_of_lines],ecx
show_token:
mov al,[esi]
test al,al
jz line_content_shown
cmp al,0Ah
je line_content_shown
cmp al,1Ah
je show_name_token
cmp al,22h
je show_string_token
cmp al,27h
je show_string_token
cmp al,'\'
jne show_basic_token
cmp byte [esi+1],0Ah
jne show_basic_token
dec [number_of_lines]
jnz show_attached_line
show_basic_token:
mov ecx,1
call display_error_string
inc esi
jmp show_token
show_name_token:
add esi,1+4
mov ecx,[esi-4]
call display_error_string
add esi,[esi-4]
add esi,12
jmp show_token
show_string_token:
mov ebx,esi
inc esi
call show_string_token_content
lea esi,[ebx+1]
lodsd
add esi,eax
jmp show_token
show_string_token_content:
lea edi,[esi+4]
mov ecx,[esi]
show_string_segment:
push ecx edi
mov esi,_single_quote
mov ecx,1
call display_error_string
pop edi ecx
jecxz show_end_quote
mov edx,ecx
mov al,27h
repne scasb
sub edx,ecx
mov esi,edi
sub esi,edx
push ecx edi
mov ecx,edx
call display_error_string
pop edi ecx
test ecx,ecx
jnz show_string_segment
show_end_quote:
cmp byte [ebx],27h
je string_token_shown
mov esi,_single_quote
mov ecx,1
call display_error_string
string_token_shown:
retn
show_attached_line:
mov ecx,1
call display_error_string
lea ebx,[esi+2]
mov esi,_line_segment_prefix
xor ecx,ecx
call display_error_string
mov esi,ebx
jmp show_token
show_line_from_macro:
mov edx,[ebx+SourceEntry.text]
mov esi,[edx+ValueDefinition.value]
mov ecx,[edx+ValueDefinition.value_length]
mov eax,[ebx+SourceEntry.line_offset]
add esi,eax
sub ecx,eax
jbe line_content_shown
call show_preprocessed_line
line_content_shown:
retn
show_preprocessed_line:
; in:
; esi - preprocessed tokens
; ecx = total length of preprocessed tokens
lea eax,[esi+ecx]
mov [preprocessed_text_end],eax
show_preprocessed_token:
cmp esi,[preprocessed_text_end]
jae preprocessed_line_shown
mov al,[esi]
test al,al
jz preprocessed_line_shown
cmp al,1Ah
je show_preprocessed_name_token
cmp al,22h
je show_preprocessed_string_token
cmp al,27h
je show_preprocessed_string_token
cmp al,30h
je show_internal_number
cmp al,40h
je show_context_token
mov ecx,1
call display_error_string
inc esi
jmp show_preprocessed_token
show_preprocessed_name_token:
inc esi
lodsd
mov ebx,esi
mov esi,eax
lodsd
mov ecx,eax
call display_error_string
mov esi,ebx
jmp show_preprocessed_token
show_preprocessed_string_token:
mov ebx,esi
mov esi,[esi+1]
call show_string_token_content
lea esi,[ebx+1+4]
jmp show_preprocessed_token
show_internal_number:
inc esi
mov edx,esi
push esi
call convert_number_back
lea esi,[edx+4]
mov ecx,[edx]
call display_error_string
pop esi
add esi,[esi]
add esi,4
jmp show_preprocessed_token
show_context_token:
add esi,1+sizeof.RecognitionContext
jmp show_preprocessed_token
preprocessed_line_shown:
retn
itoa:
; in:
; edx:eax = unsigned number
; out:
; esi - temporary buffer containing decimal digits
; ecx = length of string (number of digits)
mov edi,temporary_value+4
stosd
mov eax,edx
stosd
mov edx,temporary_value
mov dword [edx],8
call convert_number_back
lea esi,[edx+4]
mov ecx,[edx]
retn

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,651 @@
match ,{
include '../libc/struct.inc'
} match -,{
else
include 'selfhost.inc'
end match
_ equ }
include '../version.inc'
BUFFER_SIZE = 4000h
STACK_SIZE = 4000h
format MZ
heap 0
stack stack_segment:stack_top-stack_bottom
entry loader:startup
segment loader use16
startup:
mov ax,1687h
int 2Fh
or ax,ax ; DPMI installed?
jnz short no_dpmi
test bl,1 ; 32-bit programs supported?
jz short no_dpmi
mov word [cs:mode_switch],di
mov word [cs:mode_switch+2],es
mov bx,si ; allocate memory for DPMI data
mov ah,48h
int 21h
jnc switch_to_protected_mode
init_failed:
call startup_error
db 'DPMI initialization failed.',0Dh,0Ah,0
no_dpmi:
call startup_error
db '32-bit DPMI services are not available.',0Dh,0Ah,0
startup_error:
pop si
push cs
pop ds
show_message:
lodsb
test al,al
jz message_shown
mov dl,al
mov ah,2
int 21h
jmp show_message
message_shown:
mov ax,4CFFh
int 21h
switch_to_protected_mode:
mov es,ax
mov ds,[ds:2Ch]
mov ax,1
call far [cs:mode_switch] ; switch to protected mode
jc init_failed
mov cx,1
xor ax,ax
int 31h ; allocate descriptor for code
jc init_failed
mov si,ax
xor ax,ax
int 31h ; allocate descriptor for data
jc init_failed
mov di,ax
mov dx,cs
lar cx,dx
shr cx,8
or cx,0C000h
mov bx,si
mov ax,9
int 31h ; set code descriptor access rights
jc init_failed
mov dx,ds
lar cx,dx
shr cx,8
or cx,0C000h
mov bx,di
int 31h ; set data descriptor access rights
jc init_failed
mov ecx,main
shl ecx,4
mov dx,cx
shr ecx,16
mov ax,7
int 31h ; set data descriptor base address
jc init_failed
mov bx,si
int 31h ; set code descriptor base address
jc init_failed
mov cx,0FFFFh
mov dx,0FFFFh
mov ax,8 ; set segment limit to 4 GB
int 31h
jc init_failed
mov bx,di
int 31h
jc init_failed
mov ax,ds
mov ds,di
mov [main_selector],di
mov [psp_selector],es
mov gs,ax ; environment selector in GS
cli
mov ss,di
mov esp,stack_top
sti
mov es,di
mov cx,1
xor ax,ax
int 31h ; allocate descriptor for BIOS data segment
jc init_failed
mov bx,ax
mov ax,gs
lar cx,ax
shr cx,8
mov ax,9
int 31h ; set descriptor access rights
jc init_failed
xor cx,cx
mov dx,400h
mov ax,7
int 31h ; set base address of BIOS data segment
jc init_failed
xor cx,cx
mov dx,0FFh
mov ax,8
int 31h ; set limit of BIOS data segment
jc init_failed
mov fs,bx ; BIOS data selector in FS
push si
push start
retf
mode_switch dd ?
segment main use32
start:
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
mov eax,[fs:6Ch]
mov [timer],eax
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
mov eax,[fs:6Ch]
sub eax,[timer]
mov ecx,36000
mul ecx
shrd eax,edx,16
shr edx,16
mov ecx,10
div ecx
mov [timer],edx
or edx,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,[timer]
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
mov ax,4C00h
int 21h
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
mov ax,4C02h
int 21h
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
mov ax,4C03h
int 21h
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
mov ax,4C01h
int 21h
get_arguments:
push ds
mov ds,[psp_selector]
mov esi,81h
mov edi,command_line
mov ecx,7Fh
move_command_line:
lodsb
cmp al,0Dh
je command_line_moved
stosb
loop move_command_line
command_line_moved:
pop ds
xor eax,eax
stosb
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 esi,command_line
mov edi,parameters
get_argument:
xor ah,ah
read_character:
lodsb
test al,al
jz no_more_arguments
cmp al,22h
je switch_quote
cmp ax,20h
je end_argument
stosb
jmp read_character
end_argument:
xor al,al
stosb
find_next_argument:
mov al,[esi]
test al,al
jz no_more_arguments
cmp al,20h
jne next_argument_found
inc esi
jmp find_next_argument
switch_quote:
xor ah,1
jmp read_character
next_argument_found:
cmp al,'-'
je get_option
cmp al,'/'
je get_option
cmp [source_path],0
je get_source_path
cmp [output_path],0
je get_output_path
error_in_arguments:
or al,-1
retn
get_source_path:
mov [source_path],edi
jmp get_argument
get_output_path:
mov [output_path],edi
jmp get_argument
no_more_arguments:
cmp [source_path],0
je error_in_arguments
xor al,al
stosb
retn
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
mov al,[esi]
cmp al,20h
je find_next_argument
test al,al
jnz error_in_arguments
jmp find_next_argument
set_verbose_mode:
call get_option_value
jc error_in_arguments
cmp edx,2
ja error_in_arguments
mov [verbosity_level],edx
jmp find_next_argument
set_errors_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_number_of_errors],edx
jmp find_next_argument
set_recursion_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_depth_of_stack],edx
jmp find_next_argument
set_passes_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
jmp find_next_argument
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
cmp al,20h
je option_value_ok
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:
push edi
find_command_segment:
cmp byte [esi],20h
jne command_segment_found
inc esi
jmp find_command_segment
command_segment_found:
xor ah,ah
cmp byte [esi],22h
jne measure_command_segment
inc esi
inc ah
measure_command_segment:
mov ebx,esi
scan_command_segment:
mov ecx,esi
mov al,[esi]
test al,al
jz command_segment_measured
cmp ax,20h
je command_segment_measured
cmp ax,22h
je command_segment_measured
inc esi
cmp al,22h
jne scan_command_segment
command_segment_measured:
sub ecx,ebx
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:
xchg esi,ebx
rep movsb
mov esi,ebx
sub edi,[initial_commands]
mov [initial_commands_length],edi
mov al,[esi]
test al,al
jz initial_command_ready
cmp al,20h
jne command_segment_found
initial_command_ready:
mov edi,[initial_commands]
add edi,[initial_commands_length]
mov ax,0Ah
stosw
inc [initial_commands_length]
pop edi
jmp find_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 '../malloc.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'
_logo db 'flat assembler version g.',VERSION,13,10,0
_usage db 'Usage: fasmg source [output]',13,10
db 'Optional settings:',13,10
db ' -e limit Set the maximum number of displayed errors (default 1)',13,10
db ' -p limit Set the maximum allowed number of passes (default 100)',13,10
db ' -r limit Set the maximum depth of the stack (default 10000)',13,10
db ' -v flag Enable or disable showing all lines from the stack (default 0)',13,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
include '../tables.inc'
include '../messages.inc'
align 4
include '../variables.inc'
psp_selector dw ?
main_selector dw ?
malloc_freelist dd ?
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
timestamp dq ?
timer dd ?
verbosity_level dd ?
no_logo db ?
command_line db 80h dup ?
parameters db 80h dup ?
segment buffer_segment
buffer = (buffer_segment-main) shl 4
db BUFFER_SIZE dup ?
segment stack_segment
stack_bottom = (stack_segment-main) shl 4
db STACK_SIZE dup ?
stack_top = stack_bottom + $

View File

@ -0,0 +1,22 @@
include '../../examples/x86/include/80386.inc'
macro format?.MZ?
format binary as 'exe'
include '../../examples/x86/include/format/mz.inc'
end macro
macro struct? name
macro ends?!
end namespace
esc end struc
virtual at 0
name name
sizeof.name = $
end virtual
purge ends?
end macro
esc struc name
label . : sizeof.name
namespace .
end macro

View File

@ -0,0 +1,415 @@
LINE_FEED equ 13,10
system_init:
cld
mov [malloc_freelist],0
mov ah,2Ah
int 21h
push dx cx
movzx ecx,cx
mov eax,ecx
sub eax,1970
mov ebx,365
mul ebx
mov ebp,eax
mov eax,ecx
sub eax,1969
shr eax,2
add ebp,eax
mov eax,ecx
sub eax,1901
mov ebx,100
div ebx
sub ebp,eax
mov eax,ecx
xor edx,edx
sub eax,1601
mov ebx,400
div ebx
add ebp,eax
movzx ecx,byte [esp+3]
mov eax,ecx
dec eax
mov ebx,30
mul ebx
add ebp,eax
cmp ecx,8
jbe months_correction
mov eax,ecx
sub eax,7
shr eax,1
add ebp,eax
mov ecx,8
months_correction:
mov eax,ecx
shr eax,1
add ebp,eax
cmp ecx,2
pop cx
jbe day_correction_ok
sub ebp,2
test ecx,11b
jnz day_correction_ok
xor edx,edx
mov eax,ecx
mov ebx,100
div ebx
or edx,edx
jnz day_correction
mov eax,ecx
mov ebx,400
div ebx
or edx,edx
jnz day_correction_ok
day_correction:
inc ebp
day_correction_ok:
pop dx
movzx eax,dl
dec eax
add eax,ebp
mov ebx,24
mul ebx
push eax
mov ah,2Ch
int 21h
pop eax
push dx
movzx ebx,ch
add eax,ebx
mov ebx,60
mul ebx
movzx ebx,cl
add eax,ebx
mov ebx,60
mul ebx
pop bx
movzx ebx,bh
add eax,ebx
adc edx,0
mov dword [timestamp],eax
mov dword [timestamp+4],edx
retn
system_shutdown:
; call mcheck
retn
dos_int:
push 0
push 0
push 0
pushw buffer_segment
pushw buffer_segment
stc
pushfw
push eax
push ecx
push edx
push ebx
push 0
push ebp
push esi
push edi
mov ax,300h
mov bx,21h
xor cx,cx
mov edi,esp
push es ss
pop es
int 31h
pop es
mov edi,[esp]
mov esi,[esp+4]
mov ebp,[esp+8]
mov ebx,[esp+10h]
mov edx,[esp+14h]
mov ecx,[esp+18h]
mov ah,[esp+20h]
sahf
mov eax,[esp+1Ch]
lea esp,[esp+32h]
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
mov ax,716Ch
mov bx,100000b
mov dx,1
xor cx,cx
xor si,si
call dos_int
jnc open_done
cmp ax,7100h
je old_open
stc
jmp open_done
old_open:
mov ax,3D00h
xor dx,dx
call dos_int
open_done:
mov bx,ax
pop edi esi
retn
adapt_path:
mov esi,edx
mov edi,buffer
copy_path:
lodsb
cmp al,'/'
jne path_char_ok
mov al,'\'
path_char_ok:
stosb
cmp edi,buffer+BUFFER_SIZE
jae out_of_memory
test al,al
jnz copy_path
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
mov ax,716Ch
mov bx,100001b
mov dx,10010b
xor cx,cx
xor si,si
xor di,di
call dos_int
jnc create_done
cmp ax,7100h
je old_create
stc
jmp create_done
old_create:
mov ah,3Ch
xor cx,cx
xor dx,dx
call dos_int
create_done:
mov bx,ax
pop edi esi
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push esi edi ebp
mov ebp,ecx
mov esi,edx
write_loop:
mov ecx,BUFFER_SIZE
sub ebp,BUFFER_SIZE
jnc do_write
add ebp,BUFFER_SIZE
mov ecx,ebp
xor ebp,ebp
do_write:
push ecx
mov edi,buffer
rep movsb
pop ecx
mov ah,40h
xor dx,dx
call dos_int
or ebp,ebp
jnz write_loop
pop ebp edi esi
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push esi edi ebp
mov ebp,ecx
mov edi,edx
read_loop:
mov ecx,BUFFER_SIZE
sub ebp,BUFFER_SIZE
jnc do_read
add ebp,BUFFER_SIZE
mov ecx,ebp
xor ebp,ebp
do_read:
push ecx
mov ah,3Fh
xor dx,dx
call dos_int
cmp ax,cx
jne read_eof
mov esi,buffer
pop ecx
rep movsb
or ebp,ebp
jnz read_loop
read_done:
pop ebp edi esi
ret
read_eof:
pop ecx
stc
jmp read_done
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
mov ah,3Eh
int 21h
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
mov dx,ax
xchg ecx,eax
shr ecx,16
mov ah,42h
int 21h
pushf
shl edx,16
popf
mov dx,ax
mov eax,edx
xor edx,edx
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,1
jmp write_string
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,2
write_string:
test ecx,ecx
jnz string_length_ok
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
string_length_ok:
mov edx,esi
call write
pop ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ebx esi edi
mov ebx,esi
xor esi,esi
compare_variable_names:
mov edx,ebx
compare_name_character:
lods byte [gs:esi]
mov ah,[edx]
inc edx
cmp al,'='
je end_of_variable_name
test ah,ah
jz next_variable
sub ah,al
jz compare_name_character
cmp ah,20h
jne next_variable
cmp al,41h
jb next_variable
cmp al,5Ah
jna compare_name_character
next_variable:
lods byte [gs:esi]
test al,al
jnz next_variable
cmp byte [gs:esi],0
jne compare_variable_names
mov ah,al
end_of_variable_name:
test ah,ah
jnz next_variable
add ecx,edi
mov edx,esi
copy_variable_value:
lods byte [gs:esi]
cmp edi,ecx
jae variable_value_next_character
stosb
variable_value_next_character:
or al,al
jnz copy_variable_value
lea eax,[esi-1]
sub eax,edx
pop edi esi ebx
ret
VALLOC_MIN = 40000h
valloc:
; in: ecx = requested minimum size
; out: eax - allocated block, ecx = allocated size, zero if failed
; preserves: ebx, esi, edi
cmp ecx,VALLOC_MIN
jbe valloc_size_minimum
dec ecx
and ecx,(-1) shl 12
add ecx,1 shl 12
jmp valloc_size_ready
valloc_size_minimum:
mov ecx,VALLOC_MIN
valloc_size_ready:
push ebx esi edi
push ecx
mov ebx,ecx
shr ebx,16
mov ax,501h
int 31h
movzx eax,cx
pop ecx
jc valloc_failed
shl ebx,16
or eax,ebx
mov edx,main
shl edx,4
sub eax,edx
pop edi esi ebx
ret
valloc_failed:
xor ecx,ecx
pop edi esi ebx
retn

View File

@ -0,0 +1,177 @@
struct Error
flags dd ? ; ERR_#
message dd ?
symbol dd ?
preprocessed_data dd ?
preprocessed_length dd ?
next dd ? ; pointer to another Error
; source SourceContext
ends
ERR_CUSTOM = 1
register_volatile_error:
; in:
; edx - 32-bit length followed by string data
; ebx - data for message formatting (only relevant for non-custom messages that contain % character)
; out:
; edx - Error
; preserves: eax, ebx, ecx, esi, edi
cmp [next_pass_needed],0
jne error_ignored
push eax ebx ecx esi edi
or [message_volatile],1
jmp get_error_line
register_delayed_error:
; in:
; edx - error message
; esi - SourceContext
; ebx - data for message formatting (only relevant for non-custom messages that contain % character)
; out:
; edx - Error
; preserves: eax, ebx, ecx, esi, edi
cmp [next_pass_needed],0
jne error_ignored
push eax ebx ecx esi edi
and [message_volatile],0
and [error_line_start],0
and [error_line_end],0
jmp add_error
register_error:
; in:
; edx - error message
; ebx - data for message formatting (only relevant for non-custom messages that contain % character)
; out:
; edx - Error, null when error was not registered
; preserves: eax, ebx, ecx, esi, edi
cmp [next_pass_needed],0
jne error_ignored
push eax ebx ecx esi edi
and [message_volatile],0
get_error_line:
mov eax,[line_start]
mov [error_line_start],eax
mov ecx,[line_end]
cmp [number_of_line_embeddings],0
je error_line_end_ok
mov eax,[line_embeddings]
mov ecx,[eax+LineEmbedding.previous_end]
error_line_end_ok:
mov [error_line_end],ecx
xor esi,esi
add_error:
mov [error_symbol],ebx
lea ebx,[first_error]
xor ecx,ecx
find_last_error:
mov eax,[ebx]
test eax,eax
jz last_error_found
lea ebx,[eax+Error.next]
inc ecx
cmp ecx,[maximum_number_of_errors]
jb find_last_error
pop edi esi ecx ebx eax
xor edx,edx
retn
last_error_found:
cmp [message_volatile],0
jne prepare_volatile_error
test esi,esi
jnz prepare_error
mov esi,[source_context]
prepare_error:
mov ecx,[esi+SourceContext.number_of_entries]
imul ecx,sizeof.SourceEntry
add ecx,sizeof.SourceContext
cmp [esi+ecx-sizeof.SourceEntry+SourceEntry.type],SOURCE_CALM
jne error_source_context_ready
mov eax,[calm_instruction_number]
mov [esi+ecx-sizeof.SourceEntry+SourceEntry.line_number],eax
and [error_line_start],0
and [error_line_end],0
error_source_context_ready:
add ecx,sizeof.Error
add ecx,[error_line_end]
sub ecx,[error_line_start]
mov edi,edx
call malloc
mov [ebx],eax
mov [eax+Error.message],edi
mov ecx,[error_symbol]
mov [eax+Error.symbol],ecx
xor ecx,ecx
mov [eax+Error.flags],ecx
mov [eax+Error.next],ecx
lea edi,[eax+sizeof.Error]
push eax
call clone_source_context
pop edx
store_preprocessed_data:
mov [edx+Error.preprocessed_data],edi
mov esi,[error_line_start]
mov ecx,[error_line_end]
sub ecx,esi
mov [edx+Error.preprocessed_length],ecx
rep movsb
pop edi esi ecx ebx eax
retn
error_ignored:
xor edx,edx
retn
prepare_volatile_error:
mov esi,edx
mov eax,[source_context]
mov ecx,[eax+SourceContext.number_of_entries]
imul ecx,sizeof.SourceEntry
add ecx,sizeof.SourceContext
cmp [eax+ecx-sizeof.SourceEntry+SourceEntry.type],SOURCE_CALM
jne volatile_error_source_context_ready
mov edx,[calm_instruction_number]
mov [eax+ecx-sizeof.SourceEntry+SourceEntry.line_number],edx
and [error_line_start],0
and [error_line_end],0
volatile_error_source_context_ready:
add ecx,sizeof.Error
add ecx,[error_line_end]
sub ecx,[error_line_start]
mov edi,ecx
add ecx,[esi]
inc ecx
call malloc
add edi,eax
mov [ebx],eax
mov edx,eax
mov [edx+Error.message],edi
xor eax,eax
mov [edx+Error.next],eax
mov [edx+Error.flags],eax
lodsd
mov ecx,eax
rep movsb
xor al,al
stosb
mov esi,[source_context]
lea edi,[edx+sizeof.Error]
push edx
call clone_source_context
pop edx
jmp store_preprocessed_data
discard_errors:
mov eax,[first_error]
test eax,eax
jnz discard_error
retn
discard_error:
add eax,sizeof.Error
call release_source_context
sub eax,sizeof.Error
mov ebx,[eax+Error.next]
call mfree
mov eax,ebx
test eax,eax
jnz discard_error
mov [first_error],eax
retn

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
macro ccall proc*,[arg]
{
common
local size,count
mov ebp,esp
if size
sub esp,size
end if
and esp,0FFFFFFF0h
count = 0
if ~ arg eq
forward
mov dword [esp+count*4],arg
count = count + 1
common
end if
size = count*4
call proc
mov esp,ebp
}
macro cinvoke proc*,arg& { ccall [proc],arg }

View File

@ -0,0 +1,499 @@
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

View File

@ -0,0 +1,60 @@
include '../../examples/x86/include/80386.inc'
macro format?.ELF? variant
match , variant
format binary as 'o'
include '../../examples/x86/include/format/elf32.inc'
use32
else match =executable? settings, variant:
match brand =at? base:, settings
ELF.Settings.ABI = brand
ELF.Settings.BaseAddress = base
else match =at? base:, settings
ELF.Settings.BaseAddress = base
else match brand:, settings
ELF.Settings.ABI = brand
end match
include '../../examples/x86/include/format/elfexe.inc'
use32
else
err 'invalid argument'
end match
end macro
macro struct? name
macro ends?!
end namespace
esc end struc
virtual at 0
name name
sizeof.name = $
end virtual
purge ends?
end macro
esc struc name
label . : sizeof.name
namespace .
end macro
macro ccall? proc*,args&
local size
mov ebp,esp
if size
sub esp,size
end if
and esp,0FFFFFFF0h
match any, args
iterate arg, args
mov dword [esp+(%-1)*4],arg
if % = 1
size := %%*4
end if
end iterate
else
size := 0
end match
call proc
mov esp,ebp
end macro

View File

@ -0,0 +1,17 @@
macro struct name*
{
local body
define body struc name \{
irp d, db,rb,dw,rw,dd,rd,dq,rq \{ struc d value& \\{ define body \\\.\\#. d value \\} \}
macro ends
\{
define body \\}
irp d, db,rb,dw,rw,dd,rd,dq,rq \\{ restruc d \\}
irpv line, body \\{ line \\}
virtual at 0
name name
sizeof.#name = $
end virtual
\}
}

View File

@ -0,0 +1,225 @@
LINE_FEED = 0Ah
system_init:
ccall libc.time,timestamp
retn
system_shutdown:
retn
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
; note:
; use of malloc_fixed hints that block will be kept as is until the end of assembly
; use of malloc_growable hints that block is likely to be resized
push ebx ecx esi edi
ccall libc.malloc,ecx
pop edi esi ecx ebx
test eax,eax
jz out_of_memory
retn
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.realloc,eax,ecx
pop edi esi ecx ebx
test eax,eax
jz out_of_memory
retn
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz interface_error
cmp eax,-1
je interface_error
push ebx esi edi
ccall libc.free,eax
pop edi esi ebx
clc
retn
interface_error:
stc
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
ccall libc.fopen,ebx,_open_mode
pop edi esi
test eax,eax
jz interface_error
mov ebx,eax
clc
retn
adapt_path:
xor ecx,ecx
mov ebx,path_buffer
copy_path:
mov al,[edx+ecx]
cmp al,'\'
jne path_char_ok
mov al,'/'
path_char_ok:
cmp ecx,1000h
jae out_of_memory
mov [ebx+ecx],al
inc ecx
test al,al
jnz copy_path
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
ccall libc.fopen,ebx,_create_mode
pop edi esi
test eax,eax
jz interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.fwrite,edx,1,ecx,ebx
pop edi esi ecx ebx
cmp eax,ecx
jne interface_error
clc
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.fread,edx,1,ecx,ebx
pop edi esi ecx ebx
cmp eax,ecx
jne interface_error
clc
ret
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
ccall libc.fclose,ebx
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
test edx,edx
jnz interface_error
push esi edi ebx
movzx ecx,cl
ccall libc.fseek,ebx,eax,ecx
test eax,eax
jnz lseek_error
mov ebx,[esp]
ccall libc.ftell,ebx
cmp eax,-1
je lseek_error
xor edx,edx
pop ebx edi esi
clc
ret
lseek_error:
pop ebx edi esi
stc
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
ccall libc.write,1,esi,ecx
pop esi ebx
retn
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi
test ecx,ecx
jnz write_string_to_stderr
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stderr:
ccall libc.write,2,esi,ecx
pop esi ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall getenv,esi
pop edi esi ecx ebx
test eax,eax
jz no_environment_variable
push esi
mov esi,eax
xor eax,eax
copy_environment_variable:
mov dl,[esi+eax]
cmp eax,ecx
jae next_environment_variable_character
mov [edi+eax],dl
next_environment_variable_character:
inc eax
test dl,dl
jnz copy_environment_variable
pop esi
environment_variable_ok:
ret
no_environment_variable:
mov eax,1
jecxz environment_variable_ok
and byte [edi],0
ret

View File

@ -0,0 +1,513 @@
match ,{
include '../libc/struct.inc'
} match -,{
else
include 'selfhost.inc'
end match
_ equ }
format ELF executable 3
entry start
include '../version.inc'
struct timeval
time_t dd ?
suseconds_t dd ?
ends
segment readable executable
start:
mov ecx,[esp]
mov [argc],ecx
lea ebx,[esp+4]
mov [argv],ebx
lea esi,[esp+4+ecx*4+4]
mov [env],esi
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
mov eax,78 ; sys_gettimeofday
mov ebx,start_time
xor ecx,ecx
int 0x80
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
mov eax,78 ; sys_gettimeofday
mov ebx,end_time
xor ecx,ecx
int 0x80
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
xor ebx,ebx
mov eax,1 ; sys_exit
int 0x80
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
mov ebx,2
mov eax,1 ; sys_exit
int 0x80
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
mov ebx,3
mov eax,1 ; sys_exit
int 0x80
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
mov ebx,1
mov eax,1 ; sys_exit
int 0x80
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 '../malloc.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'
segment readable
_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'
segment readable writeable
align 16
include '../variables.inc'
align 16
timestamp dq ?
loff dq ?
argc dd ?
argv dd ?
env dd ?
mmap_args rd 6
malloc_freelist dd ?
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
start_time timeval
end_time timeval
tenths_of_second dd ?
verbosity_level dd ?
no_logo db ?
path_buffer rb 1000h
segment readable writeable gnustack

View File

@ -0,0 +1,59 @@
include '../../examples/x86/include/80386.inc'
macro format?.ELF? variant
match , variant
format binary as 'o'
include '../../examples/x86/include/format/elf32.inc'
use32
else match =executable? settings, variant:
match brand =at? base:, settings
ELF.Settings.ABI = brand
ELF.Settings.BaseAddress = base
else match =at? base:, settings
ELF.Settings.BaseAddress = base
else match brand:, settings
ELF.Settings.ABI = brand
end match
include '../../examples/x86/include/format/elfexe.inc'
use32
else
err 'invalid argument'
end match
end macro
macro struct? name
macro ends?!
end namespace
esc end struc
virtual at 0
name name
sizeof.name = $
end virtual
purge ends?
end macro
esc struc name
label . : sizeof.name
namespace .
end macro
macro cinvoke? proc*,args&
local size
mov ebp,esp
if size
sub esp,size
end if
and esp,0FFFFFFF0h
match any, args
iterate arg, args
mov dword [esp+(%-1)*4],arg
if % = 1
size := %%*4
end if
end iterate
else
size := 0
end match
call [proc]
mov esp,ebp
end macro

View File

@ -0,0 +1,298 @@
LINE_FEED = 0Ah
O_ACCMODE = 0003o
O_RDONLY = 0000o
O_WRONLY = 0001o
O_RDWR = 0002o
O_CREAT = 0100o
O_EXCL = 0200o
O_NOCTTY = 0400o
O_TRUNC = 1000o
O_APPEND = 2000o
O_NONBLOCK = 4000o
S_ISUID = 4000o
S_ISGID = 2000o
S_ISVTX = 1000o
S_IRUSR = 0400o
S_IWUSR = 0200o
S_IXUSR = 0100o
S_IRGRP = 0040o
S_IWGRP = 0020o
S_IXGRP = 0010o
S_IROTH = 0004o
S_IWOTH = 0002o
S_IXOTH = 0001o
system_init:
mov eax,13 ; sys_time
mov ebx,timestamp
int 0x80
retn
system_shutdown:
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi ebp
call adapt_path
mov eax,5 ; sys_open
mov ecx,O_RDONLY
xor edx,edx
int 0x80
pop ebp edi esi
test eax,eax
js interface_error
mov ebx,eax
clc
retn
adapt_path:
xor ecx,ecx
mov ebx,path_buffer
copy_path:
mov al,[edx+ecx]
cmp al,'\'
jne path_char_ok
mov al,'/'
path_char_ok:
cmp ecx,1000h
jae out_of_memory
mov [ebx+ecx],al
inc ecx
test al,al
jnz copy_path
retn
interface_error:
stc
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi ebp
call adapt_path
mov eax,5 ; sys_open
mov ecx,O_CREAT+O_TRUNC+O_WRONLY
mov edx,S_IRUSR+S_IWUSR+S_IRGRP+S_IROTH
int 0x80
pop ebp edi esi
test eax,eax
js interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi ebp
mov eax,4 ; sys_write
xchg ecx,edx
int 0x80
pop ebp edi esi ecx ebx
test eax,eax
js interface_error
cmp eax,ecx
jne interface_error
clc
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi ebp
mov eax,3 ; sys_read
xchg ecx,edx
int 0x80
pop ebp edi esi ecx ebx
test eax,eax
js interface_error
cmp eax,ecx
jne interface_error
clc
ret
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
push ebx esi edi ebp
mov eax,6 ; sys_close
int 0x80
pop ebp edi esi ebx
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
test edx,edx
jnz interface_error
push esi edi ebx ebp
movzx edi,cl
mov ecx,edx
mov edx,eax
mov eax,140 ; sys_llseek
mov esi,loff
int 0x80
pop ebp ebx edi esi
test eax,eax
js interface_error
mov eax,dword [loff]
mov edx,dword [loff+4]
clc
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi ebp
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
mov eax,4 ; sys_write
mov ebx,1
mov edx,ecx
mov ecx,esi
int 0x80
pop ebp esi ebx
retn
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi ebp
test ecx,ecx
jnz write_string_to_stderr
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stderr:
mov eax,4 ; sys_write
mov ebx,2
mov edx,ecx
mov ecx,esi
int 0x80
pop ebp esi ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ebx ecx
mov edx,[env]
scan_environment:
mov ebx,[edx]
test ebx,ebx
jz no_environment_variable
xor ecx,ecx
compare_character:
mov al,[ebx+ecx]
mov ah,[esi+ecx]
inc ecx
cmp al,'='
je end_of_variable_name
test ah,ah
jz next_variable
sub ah,al
je compare_character
cmp ah,20h
jne next_variable
cmp al,'A'
jb next_variable
cmp al,'Z'
jna compare_character
next_variable:
add edx,4
jmp scan_environment
end_of_variable_name:
test ah,ah
jnz next_variable
add ebx,ecx
pop ecx
xor eax,eax
copy_environment_variable:
mov dl,[ebx+eax]
cmp eax,ecx
jae next_environment_variable_character
mov [edi+eax],dl
next_environment_variable_character:
inc eax
test dl,dl
jnz copy_environment_variable
environment_variable_ok:
pop ebx
ret
no_environment_variable:
pop ecx
mov eax,1
jecxz environment_variable_ok
and byte [edi],0
pop ebx
ret
VALLOC_MINIMUM_SIZE = 100000h
valloc:
; in: ecx = requested minimum size
; out: eax - allocated block, ecx = allocated size, zero if failed
; preserves: ebx, esi, edi
cmp ecx,VALLOC_MINIMUM_SIZE
jbe valloc_size_minimum
dec ecx
and ecx,(-1) shl 12
add ecx,1 shl 12
jmp valloc_size_ready
valloc_size_minimum:
mov ecx,VALLOC_MINIMUM_SIZE
valloc_size_ready:
push ebx edi
mov ebx,mmap_args
mov edi,ebx
xor eax,eax
stosd
mov eax,ecx
stosd
mov eax,3 ; PROT_READ + PROT_WRITE
stosd
mov eax,22h ; MAP_PRIVATE + MAP_ANONYMOUS
stosd
or eax,-1
stosd
xor eax,eax
stosd
mov eax,0x5A ; old_mmap
int 0x80
cmp eax,-1
jne valloc_ok
xor ecx,ecx
valloc_ok:
pop edi ebx
retn

View File

@ -0,0 +1,124 @@
macro use32on64
{
define esp rsp
define promote.eax rax
define promote.ebx rbx
define promote.ecx rcx
define promote.edx rdx
define promote.esi rsi
define promote.edi rdi
define promote.ebp rbp
define promote.esp rsp
macro push args
\{
local list,arg,status
define list
define arg
irps sym, args \\{
define status
match =dword, sym \\\{
define status :
\\\}
match [any, status arg sym \\\{
define arg [any
match [mem], arg \\\\{
match previous, list \\\\\{ define list previous,[mem] \\\\\}
match , list \\\\\{ define list [mem] \\\\\}
define arg
\\\\}
define status :
\\\}
match [, status arg sym \\\{
define arg [
define status :
\\\}
match , status \\\{
match previous, list \\\\{ define list previous,sym \\\\}
match , list \\\\{ define list sym \\\\}
\\\}
\\}
match ops,list \\{
irp op, ops \\\{
if op eqtype eax
push promote.\\\#op
else
mov r8d,op
push r8
end if
\\\}
\\}
\}
macro pop args
\{
local list,arg,status
define list
define arg
irps sym, args \\{
define status
match =dword, sym \\\{
define status :
\\\}
match [any, status arg sym \\\{
define arg [any
match [mem], arg \\\\{
match previous, list \\\\\{ define list previous,[mem] \\\\\}
match , list \\\\\{ define list [mem] \\\\\}
define arg
\\\\}
define status :
\\\}
match [, status arg sym \\\{
define arg [
define status :
\\\}
match , status \\\{
match previous, list \\\\{ define list previous,sym \\\\}
match , list \\\\{ define list sym \\\\}
\\\}
\\}
match ops,list \\{
irp op, ops \\\{
if op eqtype eax
pop promote.\\\#op
else
pop r8
mov op,r8d
end if
\\\}
\\}
\}
irp instr, jmp,call
\{
macro instr op
\\{
if op eqtype [0]
mov r8d,op
instr r8
else if op eqtype 0
instr op
else
instr promote.\\#op
end if
\\}
\}
macro jecxz target
\{
if target-($+1) < 80h & target-($+1) >= -80h
jecxz target
else
local j,k
jecxz j
jmp k
j: jmp target
k:
end if
\}
}

View File

@ -0,0 +1,545 @@
match ,{
include '../../libc/struct.inc'
include '32on64.inc'
} match -,{
else
include 'selfhost.inc'
end match
_ equ }
format ELF64 executable 3
entry start
include '../../version.inc'
struct timeval
time_t dq ?
suseconds_t dq ?
ends
segment readable executable
start:
mov rcx,[rsp]
mov [argc],rcx
lea rbx,[rsp+8]
mov [argv],rbx
lea rsi,[rsp+8+rcx*8+8]
mov [env],rsi
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
mov eax,96 ; sys_gettimeofday
mov edi,start_time
xor esi,esi
syscall
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
mov eax,96 ; sys_gettimeofday
mov edi,end_time
xor esi,esi
syscall
mov rax,[end_time.time_t]
sub rax,[start_time.time_t]
mov rcx,1000000
mul rcx
add rax,[end_time.suseconds_t]
adc rdx,0
sub rax,[start_time.suseconds_t]
sbb rdx,0
add rax,50000
mov rcx,1000000
div rcx
mov rbx,rax
mov rax,rdx
xor rdx,rdx
mov rcx,100000
div rcx
mov [tenths_of_second],eax
xchg rax,rbx
or rbx,rax
jz display_output_length
mov rdx,rax
shr rdx,32
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 rax rdx
call itoa
call display_string
pop rdx rax
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
xor edi,edi ; exit code 0
mov eax,60 ; sys_exit
syscall
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
mov edi,2
mov eax,60 ; sys_exit
syscall
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
mov edi,3
mov eax,60 ; sys_exit
syscall
internal_error:
int3
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
mov edi,1
mov eax,60 ; sys_exit
syscall
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 rcx,[argc]
mov rbx,[argv]
add rbx,8
dec ecx
jz error_in_arguments
get_argument:
mov rsi,[rbx]
mov al,[rsi]
cmp al,'-'
je get_option
cmp [source_path],0
jne get_output_file
call strdup
mov [source_path],eax
jmp next_argument
get_output_file:
cmp [output_path],0
jne error_in_arguments
call strdup
mov [output_path],eax
jmp next_argument
get_option:
inc rsi
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 [rsi],0
je next_argument
error_in_arguments:
or al,-1
ret
set_verbose_mode:
cmp byte [rsi],0
jne get_verbose_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
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 [rsi],0
jne get_errors_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
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 [rsi],0
jne get_recursion_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
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 [rsi],0
jne get_passes_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
get_passes_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
next_argument:
add rbx,8
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 [rsi],20h
jne get_option_digit
inc rsi
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 rsi
clc
ret
invalid_option_value:
stc
ret
insert_initial_command:
cmp byte [rsi],0
jne measure_initial_command
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
measure_initial_command:
push rbx rcx rdi
mov rdi,rsi
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 rdi rcx rbx
jmp next_argument
allocate_initial_commands_buffer:
push rsi rcx
mov ecx,eax
call malloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
pop rcx rsi
jmp copy_initial_command
grow_initial_commands_buffer:
push rsi rcx
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 rcx rsi
jmp copy_initial_command
strdup:
; in: rsi - ASCIIZ string
; out: eax - copy of the string in 32-bit addressable memory
; preserves: rbx, rcx, rsi
push rbx rcx rsi
mov rdi,rsi
or ecx,-1
xor al,al
repne scasb
not ecx
push rsi rcx
call malloc
pop rcx rsi
mov edi,eax
rep movsb
pop rsi rcx rbx
ret
include 'system.inc'
use32on64
include '../../malloc.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'
segment readable
_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
include '../../tables.inc'
include '../../messages.inc'
segment readable writeable
align 16
include '../../variables.inc'
align 16
timestamp dq ?
argc dq ?
argv dq ?
env dq ?
mmap_hint dd ?
malloc_freelist dd ?
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
start_time timeval
end_time timeval
tenths_of_second dd ?
verbosity_level dd ?
no_logo db ?
local_heap_available db ?
path_buffer rb 1000h
segment readable writeable
align 1000h
LOCAL_HEAP_SIZE = 1000000h
local_heap rb LOCAL_HEAP_SIZE
segment readable writeable gnustack

View File

@ -0,0 +1,120 @@
include '../../../examples/x86/include/x64.inc'
macro format?.ELF64? variant
match , variant
format binary as 'o'
include '../../../examples/x86/include/format/elf64.inc'
use64
else match =executable? settings, variant:
ELF.Settings.Class = ELFCLASS64
ELF.Settings.Machine = EM_X86_64
ELF.Settings.BaseAddress = 400000h
match brand =at? base:, settings
ELF.Settings.ABI = brand
ELF.Settings.BaseAddress = base
else match =at? base:, settings
ELF.Settings.BaseAddress = base
else match brand:, settings
ELF.Settings.ABI = brand
end match
include '../../../examples/x86/include/format/elfexe.inc'
use64
else
err 'invalid argument'
end match
end macro
macro struct? name
macro ends?!
end namespace
esc end struc
virtual at 0
name name
sizeof.name = $
end virtual
purge ends?
end macro
esc struc name
label . : sizeof.name
namespace .
end macro
macro use32on64?
define esp rsp
define promote
iterate <reg32,reg64>, eax,rax, ebx,rbx, ecx,rcx, edx,rdx, esi,rsi, edi,rdi, esp,rsp, ebp,rbp
promote.reg32? equ reg64
end iterate
iterate instr, jmp,call
calminstruction instr? arg
local tmp
match [tmp], arg
jyes zero_extend
transform arg, promote
arrange tmp, =instr arg
assemble tmp
exit
zero_extend:
arrange tmp, =mov =r8d,[tmp]
assemble tmp
arrange tmp, =instr =r8
assemble tmp
end calminstruction
end iterate
calminstruction push? arg
local car, cdr
match car cdr?, arg
loop:
transform car, promote
jno non_reg
arrange car, =push car
assemble car
match car cdr?, cdr
jyes loop
exit
non_reg:
arrange tmp, =mov =r8d,arg
assemble tmp
arrange tmp, =push =r8
assemble tmp
exit
end calminstruction
calminstruction pop? arg
local car, cdr
match car cdr?, arg
loop:
transform car, promote
jno non_reg
arrange car, =pop car
assemble car
match car cdr?, cdr
jyes loop
exit
non_reg:
arrange tmp, =pop =r8
assemble tmp
arrange tmp, =mov arg,=r8d
assemble tmp
exit
end calminstruction
macro jecxz? target
if target-($+1) < 80h & target-($+1) >= -80h
jecxz target
else
local j,k
jecxz j
jmp k
j: jmp target
k:
end if
end macro
end macro

View File

@ -0,0 +1,334 @@
LINE_FEED = 0Ah
O_ACCMODE = 0003o
O_RDONLY = 0000o
O_WRONLY = 0001o
O_RDWR = 0002o
O_CREAT = 0100o
O_EXCL = 0200o
O_NOCTTY = 0400o
O_TRUNC = 1000o
O_APPEND = 2000o
O_NONBLOCK = 4000o
S_ISUID = 4000o
S_ISGID = 2000o
S_ISVTX = 1000o
S_IRUSR = 0400o
S_IWUSR = 0200o
S_IXUSR = 0100o
S_IRGRP = 0040o
S_IWGRP = 0020o
S_IXGRP = 0010o
S_IROTH = 0004o
S_IWOTH = 0002o
S_IXOTH = 0001o
system_init:
mov eax,201 ; sys_time
mov edi,timestamp
syscall
or [local_heap_available],1
retn
system_shutdown:
call mcheck
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push rsi rdi
call adapt_path
mov eax,2 ; sys_open
mov esi,O_RDONLY
xor edx,edx
syscall
pop rdi rsi
test eax,eax
js interface_error
mov ebx,eax
clc
ret
interface_error:
stc
ret
adapt_path:
xor ecx,ecx
mov edi,path_buffer
copy_path:
mov al,[edx+ecx]
cmp al,'\'
jne path_char_ok
mov al,'/'
path_char_ok:
cmp ecx,1000h
jae out_of_memory
mov [edi+ecx],al
inc ecx
test al,al
jnz copy_path
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push rsi rdi
call adapt_path
mov esi,O_CREAT+O_TRUNC+O_WRONLY
mov edx,S_IRUSR+S_IWUSR+S_IRGRP+S_IROTH
mov eax,2 ; sys_open
syscall
pop rdi rsi
test eax,eax
js interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push rsi rdi
mov eax,1 ; sys_write
mov edi,ebx
mov esi,edx
mov edx,ecx
syscall
pop rdi rsi
test eax,eax
js interface_error
cmp eax,edx
jne interface_error
clc
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push rsi rdi
mov eax,0 ; sys_read
mov edi,ebx
mov esi,edx
mov edx,ecx
syscall
pop rdi rsi
test eax,eax
js interface_error
cmp eax,edx
jne interface_error
clc
ret
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
push rdi
mov edi,ebx
mov eax,3 ; sys_close
syscall
pop rdi
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
push rsi rdi
mov edi,ebx
mov esi,edx
mov eax,eax
shl rsi,32
or rsi,rax
xor edx,edx
mov dl,cl
mov eax,8 ; sys_lseek
syscall
pop rdi rsi
cmp rax,-1
je interface_error
mov rdx,rax
shr rdx,32
clc
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push rbx rsi rbp
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
mov eax,1 ; sys_write
mov edi,1
mov edx,ecx
syscall
pop rbp rsi rbx
retn
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push rbx rsi rbp
test ecx,ecx
jnz write_string_to_stderr
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stderr:
mov eax,1 ; sys_write
mov edi,2
mov edx,ecx
syscall
pop rbp rsi rbx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push rbx rcx
mov rdx,[env]
scan_environment:
mov rbx,[rdx]
test rbx,rbx
jz no_environment_variable
xor ecx,ecx
compare_character:
mov al,[rbx+rcx]
mov ah,[esi+ecx]
inc ecx
cmp al,'='
je end_of_variable_name
test ah,ah
jz next_variable
sub ah,al
je compare_character
cmp ah,20h
jne next_variable
cmp al,'A'
jb next_variable
cmp al,'Z'
jna compare_character
next_variable:
add rdx,8
jmp scan_environment
end_of_variable_name:
test ah,ah
jnz next_variable
add rbx,rcx
pop rcx
xor eax,eax
copy_environment_variable:
mov dl,[rbx+rax]
cmp eax,ecx
jae next_environment_variable_character
mov [edi+eax],dl
next_environment_variable_character:
inc eax
test dl,dl
jnz copy_environment_variable
environment_variable_ok:
pop rbx
ret
no_environment_variable:
pop rcx
mov eax,1
jecxz environment_variable_ok
and byte [edi],0
pop rbx
ret
VALLOC_MINIMUM_SIZE = 100000h
valloc:
; in: ecx = requested minimum size
; out: eax - allocated block, ecx = allocated size, zero if failed
; preserves: ebx, esi, edi
cmp ecx,VALLOC_MINIMUM_SIZE
jbe valloc_size_minimum
dec ecx
and ecx,(-1) shl 12
add ecx,1 shl 12
jmp valloc_size_ready
valloc_size_minimum:
mov ecx,VALLOC_MINIMUM_SIZE
valloc_size_ready:
push rbx rsi rdi
cmp [local_heap_available],0
je valloc_mmap
cmp ecx,LOCAL_HEAP_SIZE
ja valloc_mmap
and [local_heap_available],0
mov eax,local_heap
mov ecx,LOCAL_HEAP_SIZE
jmp valloc_ok
valloc_mmap:
xor r9d,r9d
or r8,-1
mov r10d,62h ; MAP_PRIVATE + MAP_ANONYMOUS + MAP_32BIT
mov edx,3 ; PROT_READ + PROT_WRITE
mov esi,ecx
xor edi,edi
mov eax,9 ; sys_mmap
syscall
cmp eax,-1
je valloc_mmap_with_hint
mov ecx,eax
cmp rcx,rax
jne valloc_mmap_unusable
add ecx,esi
jnc mmap_ok
valloc_mmap_unusable:
mov rdi,rax
mov eax,11 ; sys_munmap
syscall
valloc_mmap_with_hint:
mov r10d,22h ; MAP_PRIVATE + MAP_ANONYMOUS
mov edx,3 ; PROT_READ + PROT_WRITE
mov edi,[mmap_hint]
mov eax,9 ; sys_mmap
syscall
cmp eax,-1
je valloc_failed
mov ecx,eax
cmp rcx,rax
jne valloc_failed
add ecx,esi
jc valloc_failed
mmap_ok:
sub ecx,eax
valloc_ok:
lea edx,[eax+ecx]
mov [mmap_hint],edx
pop rdi rsi rbx
retn
valloc_failed:
xor ecx,ecx
pop rdi rsi rbx
retn

Binary file not shown.

View File

@ -0,0 +1,504 @@
match ,{
err ; fasm 1 assembly not supported
} match -,{
else
include 'selfhost.inc'
end match
_ equ }
format MachO executable
entry start
include '../version.inc'
interpreter '/usr/lib/dyld'
uses '/usr/lib/libSystem.B.dylib'
import libc.malloc,'_malloc',\
libc.realloc,'_realloc',\
libc.free,'_free',\
libc.fopen,'_fopen',\
libc.fclose,'_fclose',\
libc.fread,'_fread',\
libc.fwrite,'_fwrite',\
libc.fseek,'_fseek',\
libc.ftell,'_ftell',\
libc.time,'_time',\
libc.write,'_write',\
getenv,'_getenv',\
gettimeofday,'_gettimeofday',\
exit,'_exit'
struct timeval
time_t dd ?
suseconds_t dd ?
ends
segment '__TEXT' readable executable
section '__text' align 16
start:
mov ecx,[esp]
mov [argc],ecx
lea ebx,[esp+4]
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 '__cstring' align 4
_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'
segment '__DATA' readable writable
section '__bss' 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

View File

@ -0,0 +1,498 @@
match ,{
err ; fasm 1 assembly not supported
} match -,{
else
include 'selfhost.inc'
end match
_ equ }
format MachO
public main as '_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' as getenv
extrn '_gettimeofday' as gettimeofday
extrn '_exit' as exit
struct timeval
time_t dd ?
suseconds_t dd ?
ends
section '__TEXT':'__text' 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 '__TEXT':'__cstring' align 4
_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 '__DATA':'__data' 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

View File

@ -0,0 +1,50 @@
include '../../examples/x86/include/80386.inc'
macro format?.MachO? variant
match , variant
MachO.Settings.FileType equ MH_OBJECT
include '../../examples/x86/include/format/macho.inc'
use32
else match =executable?, variant
MachO.Settings.BaseAddress = 0x1000
include '../../examples/x86/include/format/macho.inc'
use32
else
err 'invalid argument'
end match
end macro
macro struct? name
macro ends?!
end namespace
esc end struc
virtual at 0
name name
sizeof.name = $
end virtual
purge ends?
end macro
esc struc name
label . : sizeof.name
namespace .
end macro
macro ccall? proc*,args&
local size
mov ebp,esp
sub esp,size
and esp,0FFFFFFF0h
match any, args
iterate arg, args
mov dword [esp+(%-1)*4],arg
if % = 1
size := %%*4
end if
end iterate
else
size := 0
end match
call proc
mov esp,ebp
end macro

View File

@ -0,0 +1,225 @@
LINE_FEED = 0Ah
system_init:
ccall libc.time,timestamp
retn
system_shutdown:
retn
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
; note:
; use of malloc_fixed hints that block will be kept as is until the end of assembly
; use of malloc_growable hints that block is likely to be resized
push ebx ecx esi edi
ccall libc.malloc,ecx
pop edi esi ecx ebx
test eax,eax
jz out_of_memory
retn
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.realloc,eax,ecx
pop edi esi ecx ebx
test eax,eax
jz out_of_memory
retn
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz interface_error
cmp eax,-1
je interface_error
push ebx esi edi
ccall libc.free,eax
pop edi esi ebx
clc
retn
interface_error:
stc
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
ccall libc.fopen,ebx,_open_mode
pop edi esi
test eax,eax
jz interface_error
mov ebx,eax
clc
retn
adapt_path:
xor ecx,ecx
mov ebx,path_buffer
copy_path:
mov al,[edx+ecx]
cmp al,'\'
jne path_char_ok
mov al,'/'
path_char_ok:
cmp ecx,1000h
jae out_of_memory
mov [ebx+ecx],al
inc ecx
test al,al
jnz copy_path
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push esi edi
call adapt_path
ccall libc.fopen,ebx,_create_mode
pop edi esi
test eax,eax
jz interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.fwrite,edx,1,ecx,ebx
pop edi esi ecx ebx
cmp eax,ecx
jne interface_error
clc
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall libc.fread,edx,1,ecx,ebx
pop edi esi ecx ebx
cmp eax,ecx
jne interface_error
clc
ret
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
ccall libc.fclose,ebx
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
test edx,edx
jnz interface_error
push esi edi ebx
movzx ecx,cl
ccall libc.fseek,ebx,eax,ecx
test eax,eax
jnz lseek_error
mov ebx,[esp]
ccall libc.ftell,ebx
cmp eax,-1
je lseek_error
xor edx,edx
pop ebx edi esi
clc
ret
lseek_error:
pop ebx edi esi
stc
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
ccall libc.write,1,esi,ecx
pop esi ebx
retn
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx esi
test ecx,ecx
jnz write_string_to_stderr
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stderr:
ccall libc.write,2,esi,ecx
pop esi ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ebx ecx esi edi
ccall getenv,esi
pop edi esi ecx ebx
test eax,eax
jz no_environment_variable
push esi
mov esi,eax
xor eax,eax
copy_environment_variable:
mov dl,[esi+eax]
cmp eax,ecx
jae next_environment_variable_character
mov [edi+eax],dl
next_environment_variable_character:
inc eax
test dl,dl
jnz copy_environment_variable
pop esi
environment_variable_ok:
ret
no_environment_variable:
mov eax,1
jecxz environment_variable_ok
and byte [edi],0
ret

Binary file not shown.

View File

@ -0,0 +1,546 @@
; Adapted and tested by Jacob Young (jacobly.alt@gmail.com)
match ,{
err ; fasm 1 assembly not supported
} match -,{
else
include 'selfhost.inc'
end match
_ equ }
format MachO64 executable
entry start
include '../../version.inc'
interpreter '/usr/lib/dyld'
uses '/usr/lib/libSystem.B.dylib'
import libc.fopen,'_fopen',\
libc.fclose,'_fclose',\
libc.fread,'_fread',\
libc.fwrite,'_fwrite',\
libc.fseek,'_fseek',\
libc.ftell,'_ftell',\
libc.time,'_time',\
libc.write,'_write',\
mmap,'_mmap',\
munmap,'_munmap',\
getenv,'_getenv',\
gettimeofday,'_gettimeofday',\
exit,'_exit'
struct timeval
time_t dq ?
suseconds_t dd ?,?
ends
segment '__TEXT' readable executable
section '__text' align 16
start:
mov rcx,[rsp]
mov [argc],rcx
lea rbx,[rsp+8]
mov [argv],rbx
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 rax,[end_time.time_t]
sub rax,[start_time.time_t]
mov rcx,1000000
mul rcx
mov ecx,[end_time.suseconds_t]
add ecx,50000
add rax,rcx
adc rdx,0
mov ecx,[start_time.suseconds_t]
sub rax,rcx
sbb rdx,0
mov rcx,1000000
div rcx
mov rbx,rax
mov rax,rdx
xor edx,edx
mov rcx,100000
div rcx
mov [tenths_of_second],eax
xchg rax,rbx
or rbx,rax
jz display_output_length
mov rdx,rax
shr rdx,32
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 rax rdx
call itoa
call display_string
pop rdx rax
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 rcx,[argc]
mov rbx,[argv]
add rbx,8
dec ecx
jz error_in_arguments
get_argument:
mov rsi,[rbx]
mov al,[rsi]
cmp al,'-'
je get_option
cmp [source_path],0
jne get_output_file
call strdup
mov [source_path],eax
jmp next_argument
get_output_file:
cmp [output_path],0
jne error_in_arguments
call strdup
mov [output_path],eax
jmp next_argument
get_option:
inc rsi
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 [rsi],0
je next_argument
error_in_arguments:
or al,-1
ret
set_verbose_mode:
cmp byte [rsi],0
jne get_verbose_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
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 [rsi],0
jne get_errors_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
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 [rsi],0
jne get_recursion_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
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 [rsi],0
jne get_passes_setting
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
get_passes_setting:
call get_option_value
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
next_argument:
add rbx,8
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 [rsi],20h
jne get_option_digit
inc rsi
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 rsi
clc
ret
invalid_option_value:
stc
ret
insert_initial_command:
cmp byte [rsi],0
jne measure_initial_command
dec ecx
jz error_in_arguments
add rbx,8
mov rsi,[rbx]
measure_initial_command:
push rbx rcx rdi
mov rdi,rsi
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 rdi rcx rbx
jmp next_argument
allocate_initial_commands_buffer:
push rsi rcx
mov ecx,eax
call malloc
mov [initial_commands],eax
mov [initial_commands_maximum_length],ecx
mov edi,eax
pop rcx rsi
jmp copy_initial_command
grow_initial_commands_buffer:
push rsi rcx
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 rcx rsi
jmp copy_initial_command
strdup:
; in: rsi - ASCIIZ string
; out: eax - copy of the string in 32-bit addressable memory
; preserves: rbx, rcx, rsi
push rbx rcx rsi
mov rdi,rsi
or ecx,-1
xor al,al
repne scasb
not ecx
push rsi rcx
call malloc
pop rcx rsi
mov edi,eax
rep movsb
pop rsi rcx rbx
ret
include 'system.inc'
use32on64
include '../../malloc.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 '__cstring' align 4
_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'
segment '__DATA' readable writable
section '__bss' align 4
include '../../variables.inc'
mmap_hint dd ?
malloc_freelist dd ?
source_path dd ?
output_path dd ?
maximum_number_of_passes dd ?
initial_commands dd ?
initial_commands_length dd ?
initial_commands_maximum_length dd ?
files dd ?
files_count dd ?
files_maximum_count dd ?
argc dq ?
argv dq ?
timestamp dq ?
start_time timeval
end_time timeval
tenths_of_second dd ?
verbosity_level dd ?
no_logo db ?
local_heap_available db ?
path_buffer rb 1000h
align 1000h
LOCAL_HEAP_SIZE = 1000000h
local_heap rb LOCAL_HEAP_SIZE

View File

@ -0,0 +1,41 @@
; Adapted and tested by Jacob Young (jacobly.alt@gmail.com)
include '../../linux/x64/selfhost.inc'
macro format?.MachO64? variant
match , variant
MachO.Settings.ProcessorType = CPU_TYPE_X86_64
MachO.Settings.FileType equ MH_OBJECT
include '../../../examples/x86/include/format/macho.inc'
use64
else match =executable?, variant
MachO.Settings.ProcessorType = CPU_TYPE_X86_64
MachO.Settings.BaseAddress = 0x1000
include '../../../examples/x86/include/format/macho.inc'
use64
else
err 'invalid argument'
end match
end macro
iterate reg, rdi, rsi, rdx, rcx, r8, r9
arguments.%? equ reg
end iterate
macro ccall? proc*,args&
local size
mov rbp,rsp
and rsp,0FFFFFFFFFFFFFFF0h
match any, args
iterate arg, args
if sizeof (arg)
lea arguments.%,[arg]
else if ~ arg eq arguments.%
mov arguments.%,arg
end if
end iterate
end match
call proc
mov rsp,rbp
end macro

View File

@ -0,0 +1,287 @@
; Adapted and tested by Jacob Young (jacobly.alt@gmail.com)
LINE_FEED = 0Ah
system_init:
ccall libc.time,timestamp
or [local_heap_available],1
retn
system_shutdown:
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push rsi rdi
call adapt_path
ccall libc.fopen,rbx,_open_mode
put_file_entry:
pop rdi rsi
test rax,rax
jz interface_error
push rax
mov eax,[files]
mov ecx,[files_count]
mov ebx,ecx
inc ecx
mov [files_count],ecx
cmp ecx,[files_maximum_count]
ja grow_files_buffer
store_file_entry:
pop rdx
mov [eax+ebx*8],rdx
clc
retn
interface_error:
stc
retn
grow_files_buffer:
shl ecx,4
test eax,eax
jz allocate_files_buffer
call realloc
jmp allocated_files_buffer
allocate_files_buffer:
call malloc
allocated_files_buffer:
mov [files],eax
shr ecx,3
mov [files_maximum_count],ecx
jmp store_file_entry
adapt_path:
xor ecx,ecx
mov ebx,path_buffer
copy_path:
mov al,[edx+ecx]
cmp al,'\'
jne path_char_ok
mov al,'/'
path_char_ok:
cmp ecx,1000h
jae out_of_memory
mov [ebx+ecx],al
inc ecx
test al,al
jnz copy_path
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
push rsi rdi
call adapt_path
ccall libc.fopen,rbx,_create_mode
jmp put_file_entry
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push rbx rcx rsi rdi
mov eax,[files]
mov rax,[eax+ebx*8]
ccall libc.fwrite,rdx,1,rcx,rax
pop rdi rsi rcx rbx
cmp eax,ecx
jne interface_error
clc
ret
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push rbx rcx rsi rdi
mov eax,[files]
mov rax,[eax+ebx*8]
ccall libc.fread,rdx,1,rcx,rax
pop rdi rsi rcx rbx
cmp eax,ecx
jne interface_error
clc
ret
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
push rsi rdi
mov edi,[files]
mov rdi,[edi+ebx*8]
ccall libc.fclose,rdi
pop rdi rsi
ret
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
push rsi rdi rbx
shl rdx,32
or rax,rdx
movzx ecx,cl
mov edi,[files]
mov rdi,[edi+ebx*8]
push rdi
ccall libc.fseek,rdi,rax,rcx
test eax,eax
jnz lseek_error
pop rdi
ccall libc.ftell,rdi
cmp rax,-1
je lseek_error
mov rdx,rax
shr rdx,32
mov eax,eax
pop rbx rdi rsi
clc
ret
lseek_error:
pop rbx rdi rsi
stc
ret
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push rbx rsi
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
ccall libc.write,1,rsi,rcx
pop rsi rbx
retn
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push rbx rsi
test ecx,ecx
jnz write_string_to_stderr
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stderr:
ccall libc.write,2,rsi,rcx
pop rsi rbx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push rbx rcx rsi rdi
ccall getenv,rsi
pop rdi rsi rcx rbx
test rax,rax
jz no_environment_variable
push rsi
mov rsi,rax
xor eax,eax
copy_environment_variable:
mov dl,[rsi+rax]
cmp eax,ecx
jae next_environment_variable_character
mov [edi+eax],dl
next_environment_variable_character:
inc eax
test dl,dl
jnz copy_environment_variable
pop rsi
environment_variable_ok:
ret
no_environment_variable:
mov eax,1
jecxz environment_variable_ok
and byte [edi],0
ret
VALLOC_MINIMUM_SIZE = 100000h
valloc:
; in: ecx = requested minimum size
; out: eax - allocated block, ecx = allocated size, zero if failed
; preserves: ebx, esi, edi
cmp ecx,VALLOC_MINIMUM_SIZE
jbe valloc_size_minimum
dec ecx
and ecx,(-1) shl 12
add ecx,1 shl 12
jmp valloc_size_ready
valloc_size_minimum:
mov ecx,VALLOC_MINIMUM_SIZE
valloc_size_ready:
push rbx rsi rdi
cmp [local_heap_available],0
je valloc_mmap
cmp ecx,LOCAL_HEAP_SIZE
ja valloc_mmap
and [local_heap_available],0
mov eax,local_heap
mov ecx,LOCAL_HEAP_SIZE
jmp valloc_ok
valloc_mmap:
push rcx
ccall mmap,0,rcx, \
3, \ ; PROT_READ + PROT_WRITE
9002h, \ ; MAP_PRIVATE + MAP_ANONYMOUS + MAP_32BIT
-1,0
pop rsi
cmp eax,-1
je valloc_mmap_with_hint
mov ecx,eax
cmp rcx,rax
jne valloc_mmap_unusable
add ecx,esi
jnc mmap_ok
valloc_mmap_unusable:
ccall munmap,rax,rsi
valloc_mmap_with_hint:
push rsi
mov edi,[mmap_hint]
ccall mmap,rdi,rsi, \
3, \ ; PROT_READ + PROT_WRITE
1002h, \ ; MAP_PRIVATE + MAP_ANONYMOUS
-1,0
pop rsi
cmp eax,-1
je valloc_failed
mov ecx,eax
cmp rcx,rax
jne valloc_failed
add ecx,esi
jc valloc_failed
mmap_ok:
sub ecx,eax
valloc_ok:
lea edx,[eax+ecx]
mov [mmap_hint],edx
pop rdi rsi rbx
retn
valloc_failed:
xor ecx,ecx
pop rdi rsi rbx
retn

View File

@ -0,0 +1,343 @@
; a very basic implementation of malloc/realloc
; for porting fasmg to systems that do not have such API natively
struct MemoryHeader
size dd ? ; total size of this block, the lowest bit set for blocks in use
preceding_size dd ? ; total size of the block that precedes this one in memory (zero if this is an initial block of address range)
ends
struct FreeMemory
header MemoryHeader
right dd ? ; next free block in cyclic list
left dd ? ; previous free block in cyclic list
ends
assert defined valloc
; in: ecx = requested minimum size
; out: eax - allocated block, ecx = allocated size, zero if failed
; preserves: ebx, esi, edi
; note:
; valloc is called to request raw memory from the OS;
; it is encouraged to allocate more memory than requested (even entire available memory),
; the obtained memory is kept indefinitely in the pool for malloc
; and should be released by OS automatically when the process ends;
; if the OS does not do it automatically, additional list of the memory areas
; may need to be maintained to release them before exit
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
add ecx,sizeof.MemoryHeader-1
jc out_of_memory
and ecx,(-1) shl 2
add ecx,1 shl 2
jc out_of_memory
cmp ecx,sizeof.FreeMemory
jae malloc_size_ok
mov ecx,sizeof.FreeMemory
malloc_size_ok:
mov eax,[malloc_freelist]
test eax,eax
jz malloc_new
find_fit:
cmp ecx,[eax+MemoryHeader.size]
jbe malloc_use_block
mov eax,[eax+FreeMemory.left]
cmp eax,[malloc_freelist]
jne find_fit
malloc_new:
push ecx
add ecx,sizeof.MemoryHeader
jc out_of_memory
call valloc
test ecx,ecx
jz out_of_memory
xor edx,edx
mov [eax+MemoryHeader.preceding_size],edx
pop edx
push eax
sub ecx,edx
cmp ecx,sizeof.FreeMemory+sizeof.MemoryHeader
jb no_space_for_free_block
mov [eax+MemoryHeader.size],edx
add eax,edx
mov [eax+MemoryHeader.preceding_size],edx
mov edx,ecx
sub edx,sizeof.MemoryHeader
dec edx
and edx,(-1) shl 2
add edx,1 shl 2
mov [eax+MemoryHeader.size],edx
mov ecx,[malloc_freelist]
jecxz freelist_empty
mov [eax+FreeMemory.left],ecx
mov edx,eax
xchg edx,[ecx+FreeMemory.right]
mov [eax+FreeMemory.right],edx
mov [edx+FreeMemory.left],eax
mov edx,[eax+MemoryHeader.size]
jmp free_block_ready
no_space_for_free_block:
sub ecx,sizeof.MemoryHeader
add edx,ecx
mov [eax+MemoryHeader.size],edx
jmp append_limiter
freelist_empty:
mov [eax+FreeMemory.left],eax
mov [eax+FreeMemory.right],eax
free_block_ready:
mov [malloc_freelist],eax
append_limiter:
add eax,edx
mov [eax+MemoryHeader.preceding_size],edx
mov [eax+MemoryHeader.size],sizeof.MemoryHeader or 1 ; cannot be freed
pop eax
finish_malloc:
mov ecx,[eax+MemoryHeader.size]
or [eax+MemoryHeader.size],1
add eax,sizeof.MemoryHeader
sub ecx,sizeof.MemoryHeader
retn
malloc_use_block:
mov edx,[eax+MemoryHeader.size]
sub edx,ecx
cmp edx,sizeof.FreeMemory
jb use_whole_block
mov [eax+MemoryHeader.size],ecx
mov [eax+ecx+MemoryHeader.preceding_size],ecx
add ecx,eax
mov [malloc_freelist],ecx
mov [ecx+MemoryHeader.size],edx
mov [ecx+edx+MemoryHeader.preceding_size],edx
mov edx,[eax+FreeMemory.right]
cmp edx,eax
je update_free_singleton
mov [ecx+FreeMemory.right],edx
mov [edx+FreeMemory.left],ecx
mov edx,[eax+FreeMemory.left]
mov [ecx+FreeMemory.left],edx
mov [edx+FreeMemory.right],ecx
jmp finish_malloc
update_free_singleton:
mov [ecx+FreeMemory.left],ecx
mov [ecx+FreeMemory.right],ecx
jmp finish_malloc
use_whole_block:
mov edx,[eax+FreeMemory.right]
cmp edx,eax
je depleted_freelist
mov ecx,[eax+FreeMemory.left]
mov [ecx+FreeMemory.right],edx
mov [edx+FreeMemory.left],ecx
mov [malloc_freelist],edx
jmp finish_malloc
depleted_freelist:
and [malloc_freelist],0
jmp finish_malloc
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz mfree_error
cmp eax,-1
je mfree_error
sub eax,sizeof.MemoryHeader
mov ecx,[eax+MemoryHeader.size]
btr ecx,0
jnc mfree_error
cmp ecx,sizeof.FreeMemory
jb mfree_error
cmp [eax+ecx+MemoryHeader.preceding_size],ecx
jne mfree_error
mov [eax+MemoryHeader.size],ecx
mov edx,eax
sub edx,[eax+MemoryHeader.preceding_size]
cmp edx,eax
je no_preceding_block
test [edx+MemoryHeader.size],1
jz coalesce_with_preceding_block
no_preceding_block:
test [eax+ecx+MemoryHeader.size],1
jz coalesce_with_following_block
mov ecx,[malloc_freelist]
jecxz mfree_init_freelist
mov edx,[ecx+FreeMemory.right]
mov [eax+FreeMemory.left],ecx
mov [edx+FreeMemory.left],eax
mov [eax+FreeMemory.right],edx
mov [ecx+FreeMemory.right],eax
mfree_ok:
mov [malloc_freelist],eax
clc
retn
mfree_init_freelist:
mov [eax+FreeMemory.left],eax
mov [eax+FreeMemory.right],eax
jmp mfree_ok
mfree_error:
stc
retn
coalesce_with_preceding_block:
add ecx,[edx+MemoryHeader.size]
test [edx+ecx+MemoryHeader.size],1
jz coalesce_on_both_ends
mov [edx+MemoryHeader.size],ecx
mov [edx+ecx+MemoryHeader.preceding_size],ecx
clc
retn
coalesce_on_both_ends:
lea eax,[edx+ecx]
add ecx,[eax+MemoryHeader.size]
mov [edx+MemoryHeader.size],ecx
mov [edx+ecx+MemoryHeader.preceding_size],ecx
mov [malloc_freelist],edx
mov ecx,[eax+FreeMemory.left]
mov edx,[eax+FreeMemory.right]
mov [edx+FreeMemory.left],ecx
mov [ecx+FreeMemory.right],edx
clc
retn
coalesce_with_following_block:
push ebx
lea ebx,[eax+ecx]
add ecx,[ebx+MemoryHeader.size]
mov [eax+MemoryHeader.size],ecx
mov [eax+ecx+MemoryHeader.preceding_size],ecx
mov ecx,[ebx+FreeMemory.left]
mov edx,[ebx+FreeMemory.right]
mov [ecx+FreeMemory.right],eax
mov [edx+FreeMemory.left],eax
mov ecx,[ebx+FreeMemory.left]
mov edx,[ebx+FreeMemory.right]
mov [eax+FreeMemory.left],ecx
mov [eax+FreeMemory.right],edx
pop ebx
jmp mfree_ok
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
add ecx,sizeof.MemoryHeader-1
jc out_of_memory
and ecx,(-1) shl 2
add ecx,1 shl 2
jc out_of_memory
sub eax,sizeof.MemoryHeader
mov edx,[eax+MemoryHeader.size]
and edx,not 1
cmp ecx,edx
jbe realloc_retain
test [eax+edx+MemoryHeader.size],1
jnz realloc_and_copy
add edx,[eax+edx+MemoryHeader.size]
cmp ecx,edx
ja realloc_and_copy
sub edx,ecx
cmp edx,sizeof.FreeMemory
jb append_whole_block
push esi edi
push ecx edx
lea edi,[eax+ecx]
xchg ecx,[eax+MemoryHeader.size]
and ecx,not 1
lea esi,[eax+ecx]
mov ecx,[esi+FreeMemory.left]
mov edx,[esi+FreeMemory.right]
mov [edx+FreeMemory.left],edi
mov [ecx+FreeMemory.right],edi
mov ecx,[esi+FreeMemory.left]
mov edx,[esi+FreeMemory.right]
mov [edi+FreeMemory.left],ecx
mov [edi+FreeMemory.right],edx
mov [malloc_freelist],edi
pop edx ecx
mov [edi+MemoryHeader.size],edx
mov [edi+edx+MemoryHeader.preceding_size],edx
mov [edi+MemoryHeader.preceding_size],ecx
pop edi esi
jmp finish_malloc
append_whole_block:
add edx,ecx
mov [eax+edx+MemoryHeader.preceding_size],edx
xchg edx,[eax+MemoryHeader.size]
and edx,not 1
add edx,eax
mov ecx,[edx+FreeMemory.left]
cmp ecx,edx
je depleted_freelist
mov edx,[edx+FreeMemory.right]
mov [ecx+FreeMemory.right],edx
mov [edx+FreeMemory.left],ecx
mov [malloc_freelist],ecx
jmp finish_malloc
realloc_retain:
and [eax+MemoryHeader.size],not 1
jmp finish_malloc
realloc_and_copy:
push esi edi
lea esi,[eax+sizeof.MemoryHeader]
call malloc_growable
push eax ecx
mov edi,eax
mov eax,esi
mov ecx,[esi-sizeof.MemoryHeader+MemoryHeader.size]
shr ecx,2
rep movsd
call mfree
pop ecx eax
pop edi esi
retn
if used mcheck
mcheck:
pushf
push eax ebx ecx edx
mov eax,[malloc_freelist]
test eax,eax
jz integrity_verified
verify_freelist:
mov ebx,eax
verify_preceding_blocks:
mov ecx,[ebx+MemoryHeader.preceding_size]
jecxz preceding_blocks_ok
sub ebx,ecx
mov edx,[ebx+MemoryHeader.size]
and edx,not 1
cmp ecx,edx
je verify_preceding_blocks
jmp internal_error
preceding_blocks_ok:
mov ebx,eax
verify_following_blocks:
mov ecx,[ebx+MemoryHeader.size]
and ecx,not 1
cmp ecx,sizeof.MemoryHeader
je following_blocks_ok
add ebx,ecx
cmp ecx,[ebx+MemoryHeader.preceding_size]
je verify_following_blocks
jmp internal_error
following_blocks_ok:
mov edx,[eax+FreeMemory.right]
cmp eax,[edx+FreeMemory.left]
je verify_next
jmp internal_error
verify_next:
mov eax,edx
cmp eax,[malloc_freelist]
jne verify_freelist
integrity_verified:
pop edx ecx ebx eax
popf
retn
end if

View File

@ -0,0 +1,237 @@
; this is a simple map used primarily for the source cache
struct Map
hash_mask dd ?
linked_blocks dd ?
free_space dd ?
free_space_length dd ?
ends
struct MapEntry
name dd ?
name_length dd ?
value dd ?
next_entry dd ?
ends
create_string_map:
; in: cl = number of hash bits
; out: ebx - new map
; preserves: esi
mov ebx,1
shl ebx,cl
shl ebx,2
lea ecx,[sizeof.Map+ebx*4]
call malloc_fixed
xchg ebx,eax
mov ecx,eax
dec eax
mov [ebx+Map.hash_mask],eax
lea edi,[ebx+sizeof.Map]
xor eax,eax
rep stosd
mov ecx,1000h
call malloc_fixed
mov [ebx+Map.linked_blocks],eax
xor edx,edx
mov [eax],edx
add eax,10h
mov [ebx+Map.free_space],eax
mov [ebx+Map.free_space_length],1000h-10h
retn
destroy_string_map:
; in: ebx - map
; preserves: esi, edi
mov eax,ebx
mov ebx,[ebx+Map.linked_blocks]
call mfree
free_map_blocks:
test ebx,ebx
jz string_map_destroyed
mov eax,ebx
mov ebx,[ebx]
call mfree
jmp free_map_blocks
string_map_destroyed:
retn
get_from_map:
; in:
; ebx - map
; esi - string
; ecx = string length, zero for ASCIIZ string
; out:
; eax = value
; cf set when no entry found
; preserves: ebx, [esi], edi
; note: when entry is found, esi is replaced with pointer to the same string in persistent storage
call get_bucket
test eax,eax
jz not_found_in_map
call find_map_entry
jc not_found_in_map
mov eax,[eax+MapEntry.value]
retn
get_bucket:
call hash_string
and edx,[ebx+Map.hash_mask]
mov eax,[ebx+sizeof.Map+edx*4]
retn
find_map_entry:
cmp [eax+MapEntry.name_length],ecx
jne next_map_entry
push edi
mov edi,[eax+MapEntry.name]
test edi,edi
jz not_this_map_entry
push ecx esi
repe cmpsb
pop esi ecx
jne not_this_map_entry
mov esi,edi
sub esi,ecx
pop edi
clc
retn
not_this_map_entry:
pop edi
next_map_entry:
mov eax,[eax+MapEntry.next_entry]
test eax,eax
jnz find_map_entry
not_found_in_map:
stc
retn
put_into_map:
; in:
; ebx - map
; esi - string
; ecx = string length, zero for ASCIIZ string
; eax = value
; preserves: ebx, [esi], edi
; note:
; esi is replaced with pointer to the same string in persistent storage,
; an ASCIIZ string is a key with length including the terminating zero
; and when it is put into persistent storage, final zero is copied as well
push eax
call get_bucket
test eax,eax
jz new_bucket
call find_map_entry
jnc put_value_into_map_entry
mov eax,[ebx+sizeof.Map+edx*4]
find_free_map_entry:
cmp [eax+MapEntry.name],0
je fill_map_entry
mov edx,eax
mov eax,[eax+MapEntry.next_entry]
test eax,eax
jnz find_free_map_entry
call allocate_map_entry
mov [edx+MapEntry.next_entry],eax
jmp new_map_entry
new_bucket:
call allocate_map_entry
mov [ebx+sizeof.Map+edx*4],eax
new_map_entry:
mov [eax+MapEntry.next_entry],0
fill_map_entry:
mov [eax+MapEntry.name_length],ecx
push eax
call store_string
pop eax
mov [eax+MapEntry.name],esi
put_value_into_map_entry:
pop [eax+MapEntry.value]
retn
allocate_map_entry:
mov eax,[ebx+Map.free_space]
add [ebx+Map.free_space],sizeof.MapEntry
sub [ebx+Map.free_space_length],sizeof.MapEntry
jc map_out_of_free_space
retn
map_out_of_free_space:
push ecx edx
mov ecx,1000h
call malloc_fixed
mov edx,eax
xchg [ebx+Map.linked_blocks],edx
mov [eax],edx
add eax,10h
mov [ebx+Map.free_space],eax
mov [ebx+Map.free_space_length],1000h-10h
pop edx ecx
jmp allocate_map_entry
remove_from_map:
; in:
; ebx - map
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, [esi], edi
call get_bucket
test eax,eax
jz not_found_in_map
call find_map_entry
jc not_found_in_map
mov dword [eax+MapEntry.name],0
retn
iterate_through_map:
; in:
; ebx - map
; edi - callback function
; callback:
; eax = value
; esi - string
; ecx = string length
; edx - MapEntry
mov ecx,[ebx+Map.hash_mask]
inc ecx
add ebx,sizeof.Map
iterate_through_hash_table:
mov edx,[ebx]
iterate_through_bucket:
test edx,edx
jz end_of_bucket
push ebx ecx edx edi
mov eax,[edx+MapEntry.value]
mov esi,[edx+MapEntry.name]
mov ecx,[edx+MapEntry.name_length]
call edi
pop edi edx ecx ebx
mov edx,[edx+MapEntry.next_entry]
jmp iterate_through_bucket
end_of_bucket:
add ebx,4
loop iterate_through_hash_table
retn
hash_string:
; in: esi - string, ecx = string length, zero for ASCIIZ string
; out: ecx = string length, edx = 32-bit hash
; preserves: ebx, esi, edi
mov edx,FNV_OFFSET
jecxz hash_asciiz
mov eax,ecx
hash_known_length:
xor dl,[esi]
inc esi
imul edx,FNV_PRIME
loop hash_known_length
mov ecx,eax
sub esi,ecx
retn
hash_asciiz:
inc ecx
lodsb
xor dl,al
imul edx,FNV_PRIME
test al,al
jnz hash_asciiz
hash_ready:
sub esi,ecx
retn

View File

@ -0,0 +1,52 @@
_macro_source db 'macro ',0
_preprocessed_source db 'assemble ',0
_unnamed_source db '?',0
_memory_source db 'eval',0
_space db ' ',0
_line_number_prefix db ' [',0
_line_number_suffix db ']',0
_line_content_prefix db ':'
_line_segment_prefix db LINE_FEED,9,0
_calm_source db ' (CALM)',0
_single_quote db 27h,0
_preprocessed_text_prefix db 'Processed: ',0
_error_prefix db 'Error: ',0
_custom_error_prefix db 'Custom error: ',0
_message_suffix db '.'
_new_line db LINE_FEED,0
_source_file_not_found db "source file '%s' not found",0
_error_reading_file db "error reading file '%s'",0
_missing_end_quote db "missing end quote",0
_illegal_instruction db "illegal instruction",0
_invalid_argument db "invalid argument",0
_missing_argument db "missing argument",0
_extra_characters_on_line db "extra characters on line",0
_invalid_identifier db "invalid identifier",0
_invalid_number db "invalid number",0
_undefined_symbol db "symbol '%i' is undefined or out of scope",0
_invalid_symbol_value db "the value of symbol '%i' is not valid for this use",0
_conflicting_definition db "definition of '%i' in conflict with already defined symbol",0
_cannot_apply_to_constant db "cannot apply this operation to constant",0
_symbolic_self_reference db "detected a circular reference of symbolic values",0
_unexpected_instruction db "unexpected instruction",0
_missing_end_directive db "missing end directive",0
_missing_closing_chevron db "missing closing chevron",0
_invalid_value db "value of type not allowed in this context",0
_invalid_expression db "invalid expression",0
_missing_closing_parenthesis db "missing closing parenthesis",0
_excess_closing_parenthesis db "excess closing parenthesis",0
_value_out_of_range db "value out of allowed range",0
_indeterminate_result db "expression has indeterminate, infinite, or infinitesimal result",0
_misused_variable_term db "variable term used where not expected",0
_nonlinear_polynomial db "cannot multiply variable terms",0
_subdivided_variable_term db "cannot subdivide variable term",0
_values_not_comparable db "values not comparable",0
_assertion_failed db "assertion failed",0
_area_overflow db "exceeded the maximum allowed length of output area",0
_address_out_of_range db "address out of range",0
_invalid_area db "invalid or inaccessible addressing area",0
_stack_limit_exceeded db "exceeded the maximum allowed depth of the stack",0
_repeated_declaration db "choice has already been declared",0
_undefined_jump_target db "the target of the jump is not defined in this instruction",0

View File

@ -0,0 +1,883 @@
struct OutputArea
cached_offset dq ?
definition dd ? ; pointer to ValueDefinition
ends
struct AreaHeader
flags dd ? ; AREA_#
base_address_length dd ?
uninitialized_length dd ?
ends
AREA_VIRTUAL = 1
AREA_VARIABLE = 2
AREA_SHIFT_TRACKING_DISABLED = 4
create_output_area:
; in:
; esi - base address in format of VALTYPE_NUMERIC value
; ecx = length of base address value
; out:
; ebx - AreaHeader
; edx - ValueDefinition
mov eax,[current_output_area_entry]
test eax,eax
jz create_first_output_area
push ecx
lea ecx,[eax+sizeof.OutputArea*2]
cmp ecx,[output_areas_list_end]
jbe get_next_output_entry
mov eax,[output_areas_list]
sub ecx,eax
sub [current_output_area_entry],eax
sub [initial_output_area_entry],eax
sub [output_areas_list_end],eax
call grow_stack
mov [output_areas_list],eax
add [current_output_area_entry],eax
add [initial_output_area_entry],eax
add eax,ecx
mov edi,eax
xchg [output_areas_list_end],eax
sub ecx,eax
sub edi,ecx
shr ecx,2
xor eax,eax
rep stosd
mov eax,[current_output_area_entry]
get_next_output_entry:
add eax,sizeof.OutputArea
cmp [initial_output_area_entry],0
je another_initial_output_area
mov edi,[eax-sizeof.OutputArea+OutputArea.definition]
mov ecx,[edi+ValueDefinition.value_length]
mov edi,[edi+ValueDefinition.value]
mov ebx,[edi+AreaHeader.uninitialized_length]
sub ecx,sizeof.AreaHeader
sub ecx,[edi+AreaHeader.base_address_length]
jz prior_uninitialized_length_ok
and dword [prior_uninitialized_length],0
and dword [prior_uninitialized_length+4],0
prior_uninitialized_length_ok:
add dword [prior_uninitialized_length],ebx
adc dword [prior_uninitialized_length+4],0
xor edx,edx
add ecx,ebx
adc edx,0
add ecx,dword [eax-sizeof.OutputArea+OutputArea.cached_offset]
adc edx,dword [eax-sizeof.OutputArea+OutputArea.cached_offset+4]
mov dword [eax+OutputArea.cached_offset],ecx
mov dword [eax+OutputArea.cached_offset+4],edx
pop ecx
jmp new_output_entry_ready
another_initial_output_area:
pop ecx
jmp create_initial_output_area
create_first_output_area:
mov eax,[output_areas_list]
create_initial_output_area:
mov [initial_output_area_entry],eax
and dword [eax+OutputArea.cached_offset],0
and dword [eax+OutputArea.cached_offset+4],0
and dword [prior_uninitialized_length],0
and dword [prior_uninitialized_length+4],0
new_output_entry_ready:
mov [current_output_area_entry],eax
lea ebx,[eax+OutputArea.definition]
call create_area
retn
create_area:
; in:
; ebx - where pointer to ValueDefinition should be stored, may already hold a previously used one (should contain null otherwise)
; esi - base address in format of VALTYPE_NUMERIC value
; ecx = length of base address value
; out:
; ebx - AreaHeader
; edx - ValueDefinition
mov [address_length],ecx
mov edx,[ebx]
test edx,edx
jz current_area_definition_unusable
cmp [edx+ValueDefinition.reference_count],1
je area_definition_ready
dec [edx+ValueDefinition.reference_count]
current_area_definition_unusable:
mov ecx,retired_definition
retrieve_retired_detached_value:
mov edx,[ecx]
test edx,edx
jz create_area_definition
cmp [edx+ValueDefinition.reference_count],0
jne retired_detached_value_immutable
xor eax,eax
xchg eax,[edx+ValueDefinition.previous]
mov [ecx],eax
jmp adopt_area_definition
retired_detached_value_immutable:
lea ecx,[edx+ValueDefinition.previous]
jmp retrieve_retired_detached_value
create_area_definition:
mov ecx,sizeof.ValueDefinition
call create_tree_element
mov ecx,eax
xchg ecx,[value_definition_chain]
mov [eax+ValueDefinition.interlink],ecx
mov edx,eax
adopt_area_definition:
mov [ebx],edx
or [edx+ValueDefinition.flags],VAL_DETACHED
inc [edx+ValueDefinition.reference_count]
area_definition_ready:
mov ecx,[address_length]
add ecx,sizeof.AreaHeader
mov eax,[edx+ValueDefinition.block_length]
test eax,eax
jz allocate_area_block
cmp ecx,eax
jbe initialize_area_block
push ecx edx
xor eax,eax
xchg eax,[edx+ValueDefinition.value]
call mfree
pop edx ecx
allocate_area_block:
push edx
call malloc_growable
pop edx
mov [edx+ValueDefinition.value],eax
mov [edx+ValueDefinition.block_length],ecx
initialize_area_block:
mov ebx,[edx+ValueDefinition.value]
lea edi,[ebx+sizeof.AreaHeader]
mov ecx,[address_length]
mov [ebx+AreaHeader.base_address_length],ecx
rep movsb
mov [ebx+AreaHeader.uninitialized_length],ecx
mov [ebx+AreaHeader.flags],ecx
sub edi,ebx
mov [edx+ValueDefinition.value_length],edi
mov [edx+ValueDefinition.type],VALTYPE_AREA
mov ecx,[current_pass]
mov [edx+ValueDefinition.pass],ecx
retn
initialize_output:
; in: ecx = number of bytes that should be added to output
; out: edi - output buffer to be filled with data
; preserves: esi
mov edx,[current_area]
mov ebx,[edx+ValueDefinition.value]
add ecx,[ebx+AreaHeader.uninitialized_length]
jc output_out_of_memory
mov eax,[edx+ValueDefinition.value_length]
lea edi,[ebx+eax]
add ecx,eax
jc output_out_of_memory
mov [edx+ValueDefinition.value_length],ecx
cmp ecx,[edx+ValueDefinition.block_length]
jbe area_reserve_sufficient
mov eax,[edx+ValueDefinition.value]
sub edi,eax
push edx
push ecx
bsr edx,ecx
xchg ecx,edx
dec cl
shr edx,cl
inc edx
shl edx,cl
pop ecx
cmp edx,ecx
jbe output_out_of_memory
xchg ecx,edx
call realloc
pop edx
mov ebx,eax
add edi,eax
mov [edx+ValueDefinition.value],ebx
mov [edx+ValueDefinition.block_length],ecx
area_reserve_sufficient:
mov ecx,[ebx+AreaHeader.uninitialized_length]
jecxz output_buffer_ready
xor eax,eax
rep stosb
mov [ebx+AreaHeader.uninitialized_length],eax
output_buffer_ready:
retn
output_out_of_memory:
jmp out_of_memory
uninitialized_output:
; in: ecx = number of uninitialized bytes to be added to output
; preserves: ebx, ecx, esi, edi
mov edx,[current_area]
mov eax,[edx+ValueDefinition.value]
add [eax+AreaHeader.uninitialized_length],ecx
jc area_overflow
mov edx,[edx+ValueDefinition.value_length]
sub edx,sizeof.AreaHeader
sub edx,[eax+AreaHeader.base_address_length]
add edx,[eax+AreaHeader.uninitialized_length]
jc area_overflow
retn
area_overflow:
mov edx,_area_overflow
call register_error
mov edx,[current_area]
or ecx,-1
mov eax,[edx+ValueDefinition.value]
sub ecx,[edx+ValueDefinition.value_length]
add ecx,sizeof.AreaHeader
add ecx,[eax+AreaHeader.base_address_length]
mov [eax+AreaHeader.uninitialized_length],ecx
retn
trim_output:
; preserves: ecx, esi
xor eax,eax
mov dword [prior_uninitialized_length],eax
mov dword [prior_uninitialized_length+4],eax
mov edi,[current_output_area_entry]
trim_current_output_area:
mov edx,[edi+OutputArea.definition]
mov eax,[edx+ValueDefinition.value]
and [eax+AreaHeader.uninitialized_length],0
mov ebx,[edx+ValueDefinition.value_length]
sub ebx,sizeof.AreaHeader
sub ebx,[eax+AreaHeader.base_address_length]
jnz output_trimmed
cmp edi,[initial_output_area_entry]
je output_trimmed
sub edi,sizeof.OutputArea
jmp trim_current_output_area
output_trimmed:
mov [current_output_area_entry],edi
retn
load_from_area:
; in:
; [value_length] = length of data to load
; edi - buffer for loaded data
; edx - ValueDefinition with VALTYPE_AREA
; [data_area_symbol] - SymbolTree_Leaf linked to the same ValueDefinition with update_value_link (required only for predicted loads, can be null)
; [data_offset] = offset within the area
; out:
; cf set when data could not be loaded
; when cf = 0, buffer filled with loaded data
; preserves: esi
mov eax,[edx+ValueDefinition.value]
mov ecx,[edx+ValueDefinition.pass]
cmp ecx,[current_pass]
je area_ok
test [eax+AreaHeader.flags],AREA_VARIABLE
jnz source_area_inaccessible
area_ok:
mov ebx,[data_offset]
add ebx,[eax+AreaHeader.base_address_length]
jc area_offset_unavailable
add ebx,sizeof.AreaHeader
jc area_offset_unavailable
mov ecx,[edx+ValueDefinition.value_length]
sub ecx,ebx
jb load_out_of_initialized_data
call prepare_load_length
jc area_offset_unavailable
xchg esi,ebx
add esi,eax
rep movsb
mov esi,ebx
cmp [value_length],0
je load_ok
mov ecx,[eax+AreaHeader.uninitialized_length]
jmp load_uninitialized_data
load_out_of_initialized_data:
add ecx,[eax+AreaHeader.uninitialized_length]
jc load_uninitialized_data
xor ecx,ecx
load_uninitialized_data:
call prepare_load_length
jc area_offset_unavailable
xor al,al
rep stosb
cmp [value_length],0
je load_ok
xor ebx,ebx
xchg ebx,[data_area_symbol]
test ebx,ebx
jz area_offset_unavailable
mov edx,[ebx+SymbolTree_Leaf.retired_definition]
test edx,edx
jz area_with_no_history
mov ecx,[current_pass]
sub ecx,[edx+ValueDefinition.pass]
cmp ecx,1
ja area_with_no_history
or [ebx+SymbolTree_Leaf.flags],SYM_LINK_PREDICTED
mov eax,[edx+ValueDefinition.value]
jmp load_from_area
prepare_load_length:
cmp ecx,[value_length]
jbe value_length_ok
mov ecx,[value_length]
value_length_ok:
add [data_offset],ecx
jc load_length_ready
sub [value_length],ecx
load_length_ready:
retn
source_area_inaccessible:
mov edx,_invalid_area
jmp load_failed
area_with_no_history:
or [next_pass_needed],1
area_offset_unavailable:
mov edx,_address_out_of_range
load_failed:
call register_error
stc
retn
load_ok:
clc
retn
prepare_area_to_write:
; in:
; [data_area] - ValueDefinition with VALTYPE_AREA
; [data_offset] = offset within the area
; [value_length] = length of data to be written
; out:
; cf set when writing specified length is not possible
; when cf = 0:
; edi - buffer for specified number of bytes directly within the area
; preserves: esi
mov edx,[data_area]
mov eax,[edx+ValueDefinition.value]
or [eax+AreaHeader.flags],AREA_VARIABLE
mov ebx,[data_offset]
xor ecx,ecx
add ebx,[eax+AreaHeader.base_address_length]
adc ecx,0
add ebx,sizeof.AreaHeader
adc ecx,0
add ebx,[value_length]
adc ecx,0
jnz write_outside_initialized_area
cmp ebx,[edx+ValueDefinition.value_length]
ja write_outside_initialized_area
lea edi,[eax+ebx]
mov ecx,[value_length]
sub edi,ecx
retn
area_to_write_not_accessible:
stc
retn
write_outside_initialized_area:
sub ebx,[edx+ValueDefinition.value_length]
sbb ecx,0
jnz write_outside_boundaries
sub [eax+AreaHeader.uninitialized_length],ebx
jnc extend_area
add [eax+AreaHeader.uninitialized_length],ebx
write_outside_boundaries:
push edx
mov edx,_address_out_of_range
call register_error
pop edx
test ecx,ecx
jnz area_to_write_not_accessible
test [eax+AreaHeader.flags],AREA_VIRTUAL
jz area_to_write_not_accessible
test [edx+ValueDefinition.flags],VAL_IN_USE
jnz area_to_write_not_accessible
and [eax+AreaHeader.uninitialized_length],0
extend_virtual_area:
call expand_value
jmp prepare_area_to_write
extend_area:
test [eax+AreaHeader.flags],AREA_VIRTUAL
jnz extend_virtual_area
call expand_value
call update_output_offsets
jmp prepare_area_to_write
find_output_area:
; in:
; [file_offset] = offset within the output
; out:
; cf set when not found an area that would contain a byte at specified offset
; when cf = 0:
; ebx - OutputArea
; [file_offset] = offset relative to the beginning of the found area (upper 32 bits are zero)
mov esi,[initial_output_area_entry]
mov edi,[current_output_area_entry]
add edi,sizeof.OutputArea
search_areas:
mov ebx,edi
sub ebx,esi
jz output_area_not_found
test ebx,1 shl bsf sizeof.OutputArea
jz bisect_areas_list
sub ebx,sizeof.OutputArea
bisect_areas_list:
shr ebx,1
add ebx,esi
mov eax,dword [file_offset]
mov edx,dword [file_offset+4]
sub eax,dword [ebx+OutputArea.cached_offset]
sbb edx,dword [ebx+OutputArea.cached_offset+4]
jc search_earlier_areas
jnz search_later_areas
mov edx,[ebx+OutputArea.definition]
mov ecx,[edx+ValueDefinition.value_length]
mov edx,[edx+ValueDefinition.value]
sub ecx,sizeof.AreaHeader
sub ecx,[edx+AreaHeader.base_address_length]
add ecx,[edx+AreaHeader.uninitialized_length]
cmp eax,ecx
jae search_later_areas
output_area_found:
mov dword [file_offset],eax
and dword [file_offset+4],0
; clc
retn
output_area_not_found:
stc
retn
search_later_areas:
lea esi,[ebx+sizeof.OutputArea]
jmp search_areas
search_earlier_areas:
mov edi,ebx
jmp search_areas
read_from_output:
; in:
; edi - buffer for read data
; [value_length] = length of data to read
; [file_offset] = offset within the output
; out:
; [value_length] = number of bytes that were not in the existing output and could not be read
push edi
call find_output_area
pop edi
jc output_reading_done
read_output_areas:
cmp [value_length],0
je output_reading_done
mov edx,[ebx+OutputArea.definition]
mov ecx,[edx+ValueDefinition.value_length]
mov eax,ecx
mov edx,[edx+ValueDefinition.value]
sub ecx,sizeof.AreaHeader
sub ecx,[edx+AreaHeader.base_address_length]
sub dword [file_offset],ecx
jnc initialized_load_done
lea esi,[edx+eax]
mov ecx,dword [file_offset]
add esi,ecx
neg ecx
cmp ecx,[value_length]
jbe initialized_load_length_ok
mov ecx,[value_length]
initialized_load_length_ok:
sub [value_length],ecx
rep movsb
mov dword [file_offset],ecx
initialized_load_done:
mov ecx,[edx+AreaHeader.uninitialized_length]
sub dword [file_offset],ecx
jnc uninitialized_load_done
mov ecx,dword [file_offset]
neg ecx
cmp ecx,[value_length]
jbe uninitialized_load_length_ok
mov ecx,[value_length]
uninitialized_load_length_ok:
sub [value_length],ecx
xor al,al
rep stosb
mov dword [file_offset],ecx
uninitialized_load_done:
cmp ebx,[current_output_area_entry]
je output_reading_done
add ebx,sizeof.OutputArea
jmp read_output_areas
output_reading_done:
retn
rewrite_output:
; in:
; esi - data to write
; [value_length] = length of data to write
; [file_offset] = offset within the output
; out:
; [value_length] = number of bytes that were not in the existing output and could not be rewritten
push esi
call find_output_area
pop esi
jc output_rewriting_done
rewrite_output_areas:
cmp [value_length],0
je output_rewriting_done
mov edx,[ebx+OutputArea.definition]
mov ecx,[edx+ValueDefinition.value_length]
mov edx,[edx+ValueDefinition.value]
sub ecx,sizeof.AreaHeader
sub ecx,[edx+AreaHeader.base_address_length]
mov edi,[edx+AreaHeader.uninitialized_length]
add ecx,edi
sub dword [file_offset],ecx
jnc rewrite_next_area
mov eax,[value_length]
xor ecx,ecx
add eax,edi
adc ecx,ecx
add eax,dword [file_offset]
adc ecx,0
jz rewrite_initialized_data
cmp eax,edi
jbe rewrite_uninitialized_data
mov eax,edi
rewrite_uninitialized_data:
test eax,eax
jz rewrite_initialized_data
push ebx
sub [edx+AreaHeader.uninitialized_length],eax
mov edx,[ebx+OutputArea.definition]
mov ebx,eax
call expand_value
call update_output_offsets
pop ebx
rewrite_initialized_data:
mov edx,[ebx+OutputArea.definition]
mov ecx,[edx+ValueDefinition.value_length]
mov edi,[edx+ValueDefinition.value]
or [edi+AreaHeader.flags],AREA_VARIABLE
add edi,[edi+AreaHeader.uninitialized_length]
add edi,ecx
mov ecx,dword [file_offset]
add edi,ecx
neg ecx
cmp ecx,[value_length]
jbe rewrite_length_ok
mov ecx,[value_length]
rewrite_length_ok:
sub [value_length],ecx
rep movsb
mov dword [file_offset],ecx
rewrite_next_area:
cmp ebx,[current_output_area_entry]
je output_rewriting_done
add ebx,sizeof.OutputArea
jmp rewrite_output_areas
output_rewriting_done:
retn
update_output_offsets:
; in:
; edx - ValueDefinition of output area that had some of uninitialized data made initialized
; preserves: esi
mov eax,[current_output_area_entry]
cmp edx,[eax+OutputArea.definition]
je output_offsets_ok
and dword [prior_uninitialized_length],0
and dword [prior_uninitialized_length+4],0
recount_prior_uninitialized_length:
cmp eax,[initial_output_area_entry]
je output_offsets_ok
sub eax,sizeof.OutputArea
mov edi,[eax+OutputArea.definition]
mov ebx,[edi+ValueDefinition.value]
mov ecx,[ebx+AreaHeader.uninitialized_length]
add dword [prior_uninitialized_length],ecx
adc dword [prior_uninitialized_length+4],0
cmp edx,edi
je output_offsets_ok
mov ecx,[edi+ValueDefinition.value_length]
sub ecx,sizeof.AreaHeader
sub ecx,[ebx+AreaHeader.base_address_length]
jz recount_prior_uninitialized_length
output_offsets_ok:
retn
get_current_address_value:
; out:
; esi - address in format of VALTYPE_NUMERIC value
; ecx = length of address value
; note: the returned value is placed in assembly workspace
mov eax,[current_area]
mov esi,[eax+ValueDefinition.value]
mov ebx,[eax+ValueDefinition.value_length]
mov edx,assembly_workspace
mov edi,[edx+Workspace.memory_start]
mov ecx,[esi+AreaHeader.base_address_length]
add ecx,4
call reserve_workspace
mov ecx,[esi+AreaHeader.base_address_length]
sub ebx,ecx
sub ebx,sizeof.AreaHeader
add ebx,[esi+AreaHeader.uninitialized_length]
; jc internal_error
add esi,sizeof.AreaHeader
xor eax,eax
stosd
lodsd
mov ecx,eax
xor edx,edx
jecxz offset_added_to_base_address
add_offset_to_base_address:
lodsb
add al,bl
setc dl
stosb
shr ebx,8
add ebx,edx
loop add_offset_to_base_address
offset_added_to_base_address:
mov edx,[assembly_workspace.memory_start]
add edx,4
mov eax,ebx
cmp byte [esi-1],80h
cmc
sbb eax,0
stosd
optimize_base_address:
movsx eax,byte [edi-2]
cmp ah,[edi-1]
jne base_address_ready
dec edi
cmp edi,edx
jne optimize_base_address
base_address_ready:
mov ecx,edi
sub ecx,edx
mov [edx-4],ecx
mov ecx,esi
measure_variable_terms:
lodsd
test eax,eax
jz variable_terms_measured
lodsd
add esi,eax
jmp measure_variable_terms
variable_terms_measured:
xchg ecx,esi
sub ecx,esi
rep movsb
mov esi,[assembly_workspace.memory_start]
mov ecx,edi
sub ecx,esi
retn
get_output_length:
; out:
; edx:eax = length of current output (not counting uninitialized data)
; preserves: esi
mov ebx,[current_output_area_entry]
mov eax,dword [ebx+OutputArea.cached_offset]
mov edx,dword [ebx+OutputArea.cached_offset+4]
mov edi,[ebx+OutputArea.definition]
mov ecx,[edi+ValueDefinition.value_length]
mov edi,[edi+ValueDefinition.value]
sub ecx,sizeof.AreaHeader
sub ecx,[edi+AreaHeader.base_address_length]
jz current_area_entirely_uninitialized
add eax,ecx
adc edx,0
retn
current_area_entirely_uninitialized:
sub eax,dword [prior_uninitialized_length]
sbb edx,dword [prior_uninitialized_length+4]
retn
get_output_position:
; out:
; edx:eax = current position in the output (including uninitialized data)
; preserves: esi
mov ebx,[current_output_area_entry]
mov eax,dword [ebx+OutputArea.cached_offset]
mov edx,dword [ebx+OutputArea.cached_offset+4]
mov edi,[ebx+OutputArea.definition]
mov ecx,[edi+ValueDefinition.value_length]
mov edi,[edi+ValueDefinition.value]
sub ecx,sizeof.AreaHeader
sub ecx,[edi+AreaHeader.base_address_length]
add ecx,[edi+AreaHeader.uninitialized_length]
add eax,ecx
adc edx,0
retn
create_output_path:
; in:
; ebx - base path and name
; esi - file extension
; ecx = length of the extension
; out:
; edx - output path (generated in temporary storage)
push ecx
mov edi,ebx
xor al,al
or ecx,-1
repne scasb
dec edi
mov ecx,edi
locate_extension:
cmp edi,ebx
je copy_path_name
dec edi
mov al,[edi]
cmp al,'\'
je copy_path_name
cmp al,'/'
je copy_path_name
cmp al,'.'
jne locate_extension
mov ecx,edi
copy_path_name:
sub ecx,ebx
push ecx
mov edi,[preprocessing_workspace.memory_start]
inc ecx
mov edx,preprocessing_workspace
call reserve_workspace
pop ecx
xchg esi,ebx
rep movsb
mov esi,ebx
pop ecx
mov ebx,ecx
add ecx,2
call reserve_workspace
mov ecx,ebx
jecxz extension_attached
mov al,'.'
stosb
rep movsb
extension_attached:
xor al,al
stosb
mov edx,[preprocessing_workspace.memory_start]
retn
write_output_file:
; in:
; ebx - source path
; edi - output path
; out:
; cf set when write failed
; note:
; when output path is null, source path is used with replaced or attached extension
mov [base_path],edi
xor eax,eax
mov [output_failures],eax
mov dword [uninitialized_length],eax
mov dword [uninitialized_length+4],eax
mov edx,edi
test edx,edx
jnz create_output_file
mov [base_path],ebx
mov esi,[output_extension]
mov ecx,[output_extension_length]
call create_output_path
create_output_file:
call create
jc output_write_failed
mov esi,[initial_output_area_entry]
write_area:
mov edx,[esi+OutputArea.definition]
mov eax,[edx+ValueDefinition.value]
mov ecx,[edx+ValueDefinition.value_length]
sub ecx,[eax+AreaHeader.base_address_length]
sub ecx,sizeof.AreaHeader
jz write_next_area
mov eax,dword [uninitialized_length]
or eax,dword [uninitialized_length+4]
jz write_initialized_data
write_uninitialized_data:
mov edi,[assembly_workspace.memory_start]
mov ecx,1000h shr 2
xor eax,eax
rep stosd
mov ecx,1000h
cmp dword [uninitialized_length+4],0
jne portion_length_ok
cmp ecx,dword [uninitialized_length]
jbe portion_length_ok
mov ecx,dword [uninitialized_length]
portion_length_ok:
sub dword [uninitialized_length],ecx
sbb dword [uninitialized_length+4],0
mov edx,[assembly_workspace.memory_start]
call write
jc file_write_failed
mov eax,dword [uninitialized_length]
or eax,dword [uninitialized_length+4]
jnz write_uninitialized_data
write_initialized_data:
mov edx,[esi+OutputArea.definition]
mov eax,[edx+ValueDefinition.value]
mov ecx,[edx+ValueDefinition.value_length]
mov edx,[eax+AreaHeader.base_address_length]
add edx,sizeof.AreaHeader
sub ecx,edx
add edx,eax
call write
jc file_write_failed
write_next_area:
mov edx,[esi+OutputArea.definition]
mov eax,[edx+ValueDefinition.value]
mov eax,[eax+AreaHeader.uninitialized_length]
add dword [uninitialized_length],eax
adc dword [uninitialized_length+4],0
cmp esi,[current_output_area_entry]
je close_output_file
add esi,sizeof.OutputArea
jmp write_area
close_output_file:
call close
mov ebx,[auxiliary_output_areas]
mov edi,write_auxiliary_output_area
call iterate_through_map
cmp [output_failures],0
jne output_write_failed
clc
retn
file_write_failed:
call close
output_write_failed:
stc
retn
write_auxiliary_output_area:
; in:
; eax = ValueDefinition, null for cached extension not used for auxiliary output
; esi - file extension
; ecx = length of the extension
test eax,eax
jz auxiliary_output_processed
mov ebx,[base_path]
test ebx,ebx
jz auxiliary_output_processed
push eax
call create_output_path
call create
pop edx
jc auxiliary_file_creation_failed
mov eax,[edx+ValueDefinition.value]
mov ecx,[edx+ValueDefinition.value_length]
mov edx,[eax+AreaHeader.base_address_length]
add edx,sizeof.AreaHeader
sub ecx,edx
add edx,eax
call write
jc auxiliary_file_write_failed
call close
auxiliary_output_processed:
retn
auxiliary_file_write_failed:
call close
auxiliary_file_creation_failed:
inc [output_failures]
retn

View File

@ -0,0 +1,451 @@
; note:
; to not interfere with code resolving, all external input must stay unchanged
; in subsequent passes of the assembly; for this reason all data read from files is
; permanently cached (source texts are cached in tokenized form)
struct FileData
length dq ?
cache dd ? ; pointer to FileCache
ends
struct FileCache
offset dq ?
length dd ?
next dd ? ; pointer to another FileCache
ends
read_source:
; in:
; esi - source path
; out:
; eax - tokenized source, null when file not found
; esi - source path in persistent storage
mov ebx,[file_source_cache]
xor ecx,ecx
call get_from_map
jc read_source_file
cmp eax,-1
je get_erroneous_source
retn
read_source_file:
mov edx,esi
call open
jc source_file_not_found
xor eax,eax
mov edx,eax
mov cl,2
call lseek
jc error_reading_file
test edx,edx
jnz out_of_memory
push eax
xor eax,eax
mov edx,eax
mov cl,al
call lseek
jc error_reading_file
pop ecx
inc ecx
mov [source_text_length],ecx
call malloc
mov [source_text],eax
mov edx,eax
mov ecx,[source_text_length]
dec ecx
mov byte [edx+ecx],0
call read
jc error_reading_file
call close
push esi
call tokenize_source
mov eax,[source_text]
call mfree
pop esi
mov eax,[tokenization_buffer]
xor ecx,ecx
mov ebx,[file_source_cache]
call put_into_map
mov eax,[tokenization_buffer]
retn
source_file_not_found:
xor eax,eax
xor ecx,ecx
mov ebx,[file_source_cache]
call put_into_map
xor eax,eax
retn
error_reading_file:
or eax,-1
xor ecx,ecx
mov ebx,[file_source_cache]
call put_into_map
get_erroneous_source:
mov ebx,esi
mov edx,_error_reading_file
call register_error
mov eax,zero_value
retn
use_source:
; in:
; esi - ASCIIZ source string
; out:
; eax - tokenized source
; esi - source text in persistent storage
mov edi,esi
xor al,al
or ecx,-1
repne scasb
not ecx
mov [source_text_length],ecx
mov ebx,[memory_source_cache]
xor eax,eax
call get_from_map
jc adapt_memory_source
retn
adapt_memory_source:
mov [source_text],esi
call tokenize_source
mov eax,[tokenization_buffer]
mov esi,[source_text]
mov ecx,[source_text_length]
mov ebx,[memory_source_cache]
call put_into_map
mov eax,[tokenization_buffer]
retn
tokenize_source:
; in:
; [source_text] - ASCIIZ text
; [source_text_length] = length of text (including terminating character)
; out:
; [tokenization_buffer] - tokenized source
; [tokenization_buffer_length] = length of tokenized source
mov ecx,[source_text_length]
shl ecx,1
add ecx,18
call malloc_growable
mov [tokenization_buffer],eax
mov [tokenization_buffer_length],ecx
add eax,ecx
sub eax,[source_text]
sub eax,[source_text_length]
mov [buffer_end_offset],eax
mov esi,[source_text]
mov edi,[tokenization_buffer]
mov [last_token],0Ah
tokenize:
mov eax,[buffer_end_offset]
add eax,esi
sub eax,edi
cmp eax,18
jae tokenization_buffer_reserve_ok
mov ecx,esi
sub ecx,[source_text]
mov eax,[source_text_length]
mul [tokenization_buffer_length]
div ecx
mov ecx,eax
add ecx,18
mov eax,[tokenization_buffer]
call realloc
sub edi,[tokenization_buffer]
add edi,eax
mov [tokenization_buffer],eax
mov [tokenization_buffer_length],ecx
add eax,ecx
sub eax,[source_text]
sub eax,[source_text_length]
mov [buffer_end_offset],eax
tokenization_buffer_reserve_ok:
movzx eax,byte [esi]
inc esi
mov ah,[characters+eax]
cmp ah,20h
je control_character
test ah,ah
jnz make_name_token
character_token:
stosb
mov [last_token],al
jmp tokenize
make_string_token:
mov dl,al
mov byte [edi],22h
mov [last_token],22h
add edi,5
xor ecx,ecx
copy_string:
mov al,[esi]
cmp al,0Dh
je broken_string
cmp al,0Ah
je broken_string
cmp al,1Ah
je broken_string
test al,al
jz broken_string
inc esi
cmp al,dl
jne copy_string_character
cmp byte [esi],al
jne finish_string_token
inc esi
copy_string_character:
mov [edi+ecx],al
inc ecx
jmp copy_string
broken_string:
mov byte [edi-5],27h
finish_string_token:
mov al,[edi-5]
mov [edi-4],ecx
add edi,ecx
jmp tokenize
make_name_token:
cmp al,22h
je make_string_token
cmp al,27h
je make_string_token
mov byte [edi],1Ah
mov [last_token],1Ah
add edi,5
xor ebx,ebx
mov ecx,FNV_OFFSET
mov edx,ecx
hash_name:
mov [edi+ebx],al
inc ebx
xor cl,al
xor dl,ah
imul ecx,FNV_PRIME
imul edx,FNV_PRIME
movzx eax,byte [esi]
inc esi
mov ah,[characters+eax]
cmp ah,20h
je finish_name_token
test ah,ah
jnz hash_name
finish_name_token:
mov [edi-4],ebx
add edi,ebx
mov [edi],ecx
mov [edi+4],edx
xor ecx,ecx
mov [edi+8],ecx
add edi,12
cmp ah,20h
jne character_token
control_character:
cmp al,20h
je whitespace
cmp al,9
je whitespace
cmp [last_token],20h
je mark_end_of_line
inc edi
mark_end_of_line:
mov byte [edi-1],0Ah
mov [last_token],0Ah
cmp al,0Dh
je cr
cmp al,0Ah
je lf
xor al,al
stosb
mov ecx,edi
mov eax,[tokenization_buffer]
sub ecx,eax
call realloc
mov [tokenization_buffer],eax
mov [tokenization_buffer_length],ecx
retn
cr:
cmp byte [esi],0Ah
jne tokenize
inc esi
jmp tokenize
lf:
cmp byte [esi],0Dh
jne tokenize
inc esi
jmp tokenize
whitespace:
cmp [last_token],0Ah
je tokenize
cmp [last_token],20h
je tokenize
mov al,20h
stosb
mov [last_token],al
jmp tokenize
get_file_data:
; in:
; esi - file path
; out:
; ebx - FileData, null when file not found
; esi - file path in persistent storage
; preserves: edi
mov ebx,[file_data_cache]
xor ecx,ecx
call get_from_map
jc initialize_file_data
mov ebx,eax
retn
initialize_file_data:
mov edx,esi
call open
jc remember_file_not_found
push edi
mov ecx,sizeof.FileData
call malloc_fixed
mov edi,eax
xor eax,eax
mov edx,eax
mov cl,2
call lseek
jc file_not_seekable
mov dword [edi+FileData.length],eax
mov dword [edi+FileData.length+4],edx
call close
mov eax,edi
xor ecx,ecx
mov [eax+FileData.cache],ecx
mov ebx,[file_data_cache]
call put_into_map
mov ebx,edi
pop edi
retn
file_not_seekable:
pop edi
remember_file_not_found:
xor eax,eax
mov ecx,eax
mov ebx,[file_data_cache]
call put_into_map
xor ebx,ebx
retn
read_file_data:
; in:
; esi - file path
; ebx - FileData
; edi - buffer for data
; [file_offset] = offset of data
; [data_length] = length of data
; out:
; cf set when read failed
; preserves: esi
mov [file_data],ebx
lea eax,[ebx+FileData.cache]
mov [file_cache_pointer],eax
mov ebx,[eax]
read_from_file_cache:
mov ecx,[data_length]
test ecx,ecx
jz file_data_read
test ebx,ebx
jz new_trailing_file_cache_entry
mov eax,dword [file_offset]
mov edx,dword [file_offset+4]
sub eax,dword [ebx+FileCache.offset]
sbb edx,dword [ebx+FileCache.offset+4]
jc new_file_cache_entry
jnz next_entry
mov edx,[ebx+FileCache.length]
sub edx,eax
jbe next_entry
cmp ecx,edx
jbe length_to_read_ok
mov ecx,edx
length_to_read_ok:
sub [data_length],ecx
add dword [file_offset],ecx
adc dword [file_offset+4],0
mov edx,esi
lea esi,[ebx+sizeof.FileCache+eax]
rep movsb
mov esi,edx
next_entry:
lea eax,[ebx+FileCache.next]
mov [file_cache_pointer],eax
mov ebx,[eax]
jmp read_from_file_cache
file_data_read:
clc
retn
new_trailing_file_cache_entry:
mov ebx,[file_data]
mov ecx,dword [ebx+FileData.length]
mov edx,dword [ebx+FileData.length+4]
cmp ecx,dword [file_offset]
jne measure_cache_gap
cmp edx,dword [file_offset+4]
jne measure_cache_gap
stc
retn
new_file_cache_entry:
mov ecx,dword [ebx+FileCache.offset]
mov edx,dword [ebx+FileCache.offset+4]
measure_cache_gap:
mov eax,dword [file_offset]
and eax,not 0FFFh
sub ecx,eax
sbb edx,dword [file_offset+4]
jnz compute_aligned_length
cmp ecx,[data_length]
jbe read_into_cache
compute_aligned_length:
mov eax,dword [file_offset]
and eax,0FFFh
add eax,[data_length]
dec eax
shr eax,12
inc eax
shl eax,12
test edx,edx
jnz use_aligned_length
cmp eax,ecx
jae read_into_cache
use_aligned_length:
mov ecx,eax
read_into_cache:
push ecx
add ecx,sizeof.FileCache
call malloc_fixed
mov ebx,eax
mov eax,[file_cache_pointer]
mov edx,ebx
xchg edx,[eax]
mov [ebx+FileCache.next],edx
pop [ebx+FileCache.length]
mov eax,dword [file_offset]
and eax,not 0FFFh
mov edx,dword [file_offset+4]
mov dword [ebx+FileCache.offset],eax
mov dword [ebx+FileCache.offset+4],edx
push ebx edi
mov edi,ebx
mov edx,esi
call open
jc file_access_error
mov eax,dword [edi+FileCache.offset]
mov edx,dword [edi+FileCache.offset+4]
xor cl,cl
call lseek
jc file_access_error
lea edx,[edi+sizeof.FileCache]
mov ecx,[edi+FileCache.length]
call read
jc file_access_error
call close
pop edi ebx
jmp read_from_file_cache
file_access_error:
pop edi ebx
stc
retn

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,649 @@
OPERATOR_PRECEDENCE_MASK = 3Fh
OPERATOR_UNARY = 40h
OPERATOR_RIGHT_ASSOCIATIVE = 80h
SIZE_BYTE = 1
SIZE_WORD = 2
SIZE_DWORD = 4
SIZE_PWORD = 6
SIZE_QWORD = 8
SIZE_TWORD = 10
SIZE_DQWORD = 16
SIZE_QQWORD = 32
SIZE_DQQWORD = 64
PREPOSITION_AT = 0
PREPOSITION_FROM = 1
PREPOSITION_AS = 2
PREPOSITION_DUP = 3
control_characters db 0,9,0Ah,0Dh,1Ah,20h
.count = $-control_characters
syntactical_characters db '+-/*=<>()[]{}:?!,.|&~#`\;'
.count = $-syntactical_characters
include_variable db 'INCLUDE',0
separating_operators:
db '+',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,1 + OPERATOR_UNARY
dd calculate_to_number
db '-',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,1 + OPERATOR_UNARY
dd calculate_neg
db '+',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,1
dd calculate_add
db '-',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,1
dd calculate_sub
db '*',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,2
dd calculate_mul
db '/',VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,2
dd calculate_div
db 0
symbols:
db 3,'not',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,6 + OPERATOR_UNARY
dd calculate_not
db 3,'mod',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,3
dd calculate_mod
db 3,'xor',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,4
dd calculate_xor
db 3,'and',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,4
dd calculate_and
db 2,'or',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,4
dd calculate_or
db 3,'shl',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,5
dd calculate_shl
db 3,'shr',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,5
dd calculate_shr
db 3,'bsf',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,6 + OPERATOR_UNARY
dd calculate_bsf
db 3,'bsr',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,6 + OPERATOR_UNARY
dd calculate_bsr
db 5,'bswap',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,5
dd calculate_bswap
db 7,'bappend',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,4
dd calculate_bappend
db 6,'string',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0 + OPERATOR_UNARY
dd calculate_to_string
db 5,'float',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,10 + OPERATOR_UNARY
dd calculate_to_float
db 5,'trunc',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,10 + OPERATOR_UNARY
dd extract_integer_part
db 6,'sizeof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,10 + OPERATOR_UNARY
dd extract_size
db 8,'lengthof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,10 + OPERATOR_UNARY
dd count_bytes
db 10,'elementsof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,10 + OPERATOR_UNARY
dd count_elements
db 7,'element',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,7
dd extract_element
db 5,'scale',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,7
dd extract_scale
db 8,'metadata',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,7
dd extract_metadata
db 9,'elementof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,8 + OPERATOR_RIGHT_ASSOCIATIVE
dd extract_element_reverse
db 7,'scaleof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,8 + OPERATOR_RIGHT_ASSOCIATIVE
dd extract_scale_reverse
db 10,'metadataof',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,8 + OPERATOR_RIGHT_ASSOCIATIVE
dd extract_metadata_reverse
db 7,'element',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_element
db 3,'equ',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_symbolic_variable
db 5,'reequ',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd redefine_symbolic_variable
db 6,'define',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_raw_symbolic_variable
db 8,'redefine',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd redefine_raw_symbolic_variable
db 7,'restore',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SYMCLASS_EXPRESSION
dd restore_variables
db 9,'namespace',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd set_namespace
db 7,'display',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd display_data
db 3,'err',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd custom_error
db 7,'include',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd include_source
db 4,'eval',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd evaluate_string
db 6,'assert',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd assert_condition
db 7,'defined',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_defined
db 4,'used',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_used
db 8,'definite',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_defined_earlier
db 6,'eqtype',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_type_equal
db 2,'eq',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_value_equal
db 10,'relativeto',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_COMPARATOR,VAL_INTERNAL,0
dd check_if_relative
db 2,'if',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd conditional_block
db 5,'match',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd match_block
db 6,'rmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd raw_match_block
db 8,'rawmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd raw_match_block
db 5,'while',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd conditionally_repeated_block
db 6,'repeat',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd repeated_block
db 7,'iterate',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd iterator_block
db 4,'rept',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd repeated_block
db 3,'irp',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd iterator_block
db 4,'irpv',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd variable_iterator_block
db 4,'indx',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd set_iterator_index
db 5,'break',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd break_directive
db 4,'else',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd else_directive
db 3,'end',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_directive
db 8,'postpone',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd postponed_block
db 5,'macro',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd define_macro
db 5,'struc',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd define_struc
db 3,'esc',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd escape_directive
db 5,'local',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd local_directive
db 8,'outscope',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd outscope_directive
db 5,'purge',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SYMCLASS_INSTRUCTION
dd restore_variables
db 7,'restruc',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SYMCLASS_STRUCTURE
dd restore_variables
db 7,'mvmacro',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SYMCLASS_INSTRUCTION
dd move_variable_values
db 7,'mvstruc',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SYMCLASS_STRUCTURE
dd move_variable_values
db 15,'calminstruction',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd define_calm_instruction
db 14,'removecomments',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd choose_to_remove_comments
db 14,'retaincomments',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd choose_to_retain_comments
db 12,'combinelines',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd choose_to_combine_lines
db 12,'isolatelines',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd choose_to_isolate_lines
db 3,'org',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd set_base_address
db 7,'section',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd begin_new_section
db 10,'restartout',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd restart_output
db 6,'format',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd format_directive
db 4,'emit',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_data
db 4,'emit',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_labeled_data
db 3,'dbx',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_data
db 3,'dbx',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd define_labeled_data
db 2,'db',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_BYTE
dd define_data
db 2,'db',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_BYTE
dd define_labeled_data
db 2,'dw',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_WORD
dd define_data
db 2,'dw',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_WORD
dd define_labeled_data
db 2,'dd',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DWORD
dd define_data
db 2,'dd',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DWORD
dd define_labeled_data
db 2,'dp',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_PWORD
dd define_data
db 2,'dp',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_PWORD
dd define_labeled_data
db 2,'dq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QWORD
dd define_data
db 2,'dq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QWORD
dd define_labeled_data
db 2,'dt',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_TWORD
dd define_data
db 2,'dt',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_TWORD
dd define_labeled_data
db 3,'ddq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQWORD
dd define_data
db 3,'ddq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQWORD
dd define_labeled_data
db 3,'dqq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QQWORD
dd define_data
db 3,'dqq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QQWORD
dd define_labeled_data
db 4,'ddqq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQQWORD
dd define_data
db 4,'ddqq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQQWORD
dd define_labeled_data
db 2,'rb',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_BYTE
dd reserve_data
db 2,'rb',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_BYTE
dd reserve_labeled_data
db 2,'rw',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_WORD
dd reserve_data
db 2,'rw',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_WORD
dd reserve_labeled_data
db 2,'rd',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DWORD
dd reserve_data
db 2,'rd',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DWORD
dd reserve_labeled_data
db 2,'rp',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_PWORD
dd reserve_data
db 2,'rp',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_PWORD
dd reserve_labeled_data
db 2,'rq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QWORD
dd reserve_data
db 2,'rq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QWORD
dd reserve_labeled_data
db 2,'rt',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_TWORD
dd reserve_data
db 2,'rt',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_TWORD
dd reserve_labeled_data
db 3,'rdq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQWORD
dd reserve_data
db 3,'rdq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQWORD
dd reserve_labeled_data
db 3,'rqq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QQWORD
dd reserve_data
db 3,'rqq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_QQWORD
dd reserve_labeled_data
db 4,'rdqq',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQQWORD
dd reserve_data
db 4,'rdqq',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,SIZE_DQQWORD
dd reserve_labeled_data
db 4,'file',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd include_data
db 4,'file',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd include_labeled_data
db 1,'$',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_address_value
db 2,'$$',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd base_address_value
db 2,'$@',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd truncated_address_value
db 2,'$%',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_position_value
db 3,'$%%',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd truncated_position_value
db 2,'%t',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_time_value
db 8,'__time__',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_time_value
db 10,'__source__',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd main_file_name_value
db 8,'__file__',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_file_name_value
db 8,'__line__',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_FUNCTION,VAL_INTERNAL,0
dd current_line_number_value
db 4,'byte',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_BYTE
db 4,'word',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_WORD
db 5,'dword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_DWORD
db 5,'pword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_PWORD
db 5,'fword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_PWORD
db 5,'qword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_QWORD
db 5,'tword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_TWORD
db 5,'tbyte',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_TWORD
db 6,'dqword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_DQWORD
db 5,'xword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_DQWORD
db 6,'qqword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_QQWORD
db 5,'yword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_QQWORD
db 7,'dqqword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_DQQWORD
db 5,'zword',SYMCLASS_EXPRESSION,VALTYPE_PLAIN,VAL_INTERNAL,0
dd SIZE_DQQWORD
db 5,'label',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd label_directive
db 7,'virtual',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd virtual_block
db 4,'load',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd load_value
db 5,'store',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd store_value
db 2,'at',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_PREPOSITION,VAL_INTERNAL,0
dd PREPOSITION_AT
db 4,'from',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_PREPOSITION,VAL_INTERNAL,0
dd PREPOSITION_FROM
db 2,'as',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_PREPOSITION,VAL_INTERNAL,0
dd PREPOSITION_AS
db 3,'dup',SYMCLASS_EXPRESSION,VALTYPE_NATIVE_PREPOSITION,VAL_INTERNAL,0
dd PREPOSITION_DUP
db 0
db 3,'end'
db 9,'namespace',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd end_namespace
db 2,'if',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_conditional_block
db 5,'match',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_match_block
db 6,'rmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_raw_match_block
db 8,'rawmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_raw_match_block
db 5,'while',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_conditionally_repeated_block
db 6,'repeat',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_repeated_block
db 7,'iterate',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_iterator_block
db 4,'rept',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_repeated_block
db 3,'irp',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_iterator_block
db 4,'irpv',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_variable_iterator_block
db 8,'postpone',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_postponed_block
db 5,'macro',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_macro
db 5,'struc',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd end_struc
db 7,'virtual',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd end_virtual_block
db 0
db 4,'else'
db 2,'if',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd else_conditional_block
db 5,'match',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd else_match_block
db 6,'rmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd else_raw_match_block
db 8,'rawmatch',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd else_raw_match_block
db 0
db 6,'format'
db 6,'binary',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd format_binary
db 0
db 15,'calminstruction'
db 5,'local',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_local
db 7,'arrange',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_arrange
db 5,'match',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_match
db 8,'assemble',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_assemble
db 9,'transform',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_transform
db 9,'stringify',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_stringify
db 7,'publish',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_publish
db 4,'take',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_take
db 7,'compute',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_compute
db 5,'check',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_check
db 4,'emit',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_emit
db 4,'load',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_load
db 5,'store',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_store
db 7,'display',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_display
db 3,'err',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_err
db 4,'jyes',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_jyes
db 3,'jno',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_jno
db 4,'jump',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_jump
db 4,'call',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_call
db 4,'exit',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_exit
db 3,'end',SYMCLASS_INSTRUCTION,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL + VAL_UNCONDITIONAL,0
dd alm_end
db 15,'calminstruction',SYMCLASS_STRUCTURE,VALTYPE_NATIVE_COMMAND,VAL_INTERNAL,0
dd alm_end
db 0
zero_value dd 0
dd 0
singular_value dd 1
db 1
dd 0
subtraction_operator dd EXPR_OPERATOR,calculate_sub
dd 0

View File

@ -0,0 +1,314 @@
characters db 256 dup ?
maximum_number_of_errors dd ?
maximum_depth_of_stack dd ?
variables:
temporary_value dd 4 dup ?
accumulator dd 3 dup ?
source_file dd ?
include_paths dd ?
storage_blocks dd ?
storage_free_space dd ?
storage_free_space_length dd ?
tree_blocks dd ?
tree_reserve dd ?
tree_reserve_length dd ?
value_definition_chain dd ?
retired_definition dd ?
file_source_cache dd ?
memory_source_cache dd ?
file_data_cache dd ?
operator_table dd ?
root_namespace dd ?
root_parameter_namespace dd ?
local_parameter_namespace dd ?
interceptor_symbol dd ?
label_interceptor_symbol dd ?
other_interceptor_symbol dd ?
proxy_number dd ?
source_context dd ?
source_context_maximum_length dd ?
current_pass dd ?
current_context RecognitionContext
local_namespace dd ?
parameter_namespace dd ?
directives_stack dd ?
directives_stack_base dd ?
directives_stack_end dd ?
current_counter dd ?
counters_stack_base dd ?
counters_stack_end dd ?
first_error dd ?
current_area dd ?
output_areas_list dd ?
output_areas_list_end dd ?
initial_output_area_entry dd ?
current_output_area_entry dd ?
prior_uninitialized_length dq ?
virtual_area dd ?
auxiliary_output_areas dd ?
void_symbol dd ?
base_path dd ?
output_extension dd ?
output_extension_length dd ?
output_failures dd ?
preprocessing_workspace Workspace
assembly_workspace Workspace
identifier_workspace Workspace
value_workspace Workspace
expression_workspace Workspace
calculation_workspace Workspace
auxiliary_workspace Workspace
line_start dd ?
line_end dd ?
line_embeddings dd ?
line_embeddings_maximum_length dd ?
number_of_line_embeddings dd ?
preprocessed_context dd ?
line_context dd ?
embedded_context dd ?
number_of_enclosings dd ?
recognition_context RecognitionContext
name_token dd ?
case_sensitive_hash dd ?
case_insensitive_hash dd ?
kept_symbol dd ?
current_symbol dd ?
tree_stack_base dd ?
tree_stack_end dd ?
symbol_root dd ?
symbol_branch dd ?
minor_identifier dd ?
source_end dd ?
symbol_start dd ?
symbol_data dd ?
symbol_value_start dd ?
symbol_value_end dd ?
interceptor dd ?
label_branch dd ?
label_leaf dd ?
label_interceptor dd ?
label_instruction_start dd ?
label_instruction_context dd ?
display_buffer dd ?
display_buffer_length dd ?
display_data_length dd ?
macro_buffer dd ?
macro_buffer_length dd ?
macro_leaf dd ?
macro_end_position dd ?
constituent_symbol dd ?
constituent_value dd ?
constituent_whitespace dd ?
alm_namespace dd ?
alm_adjusted_context RecognitionContext
calm_code_buffer Workspace
calm_code_cursor dd ?
calm_literals_buffer Workspace
calm_literals_cursor dd ?
calm_auxiliary_buffer Workspace
calm_auxiliary_cursor dd ?
calm_line_number dd ?
calm_instruction_number dd ?
calm_value dd ?
calm_literals dd ?
calm_source_pointer dd ?
calm_rollback_offset dd ?
value_position dd ?
kept_value dd ?
converter_position dd ?
expression_position dd ?
expression_end dd ?
operator_stack dd ?
operator_stack_position dd ?
operator_stack_base dd ?
operator_stack_end dd ?
calculation_position dd ?
source_term dd ?
destination_term dd ?
temporary_terms dd ?
free_temporary_terms dd ?
temporary_floats dd ?
iterations dd ?
exponent dd ?
multiplier dd ?
divisor dd ?
long_dividend_term dd ?
long_divisor_term dd ?
long_divisor_length dd ?
division_temporary_terms dd ?
mantissa_tail dd ?
predicted_shift dd ?
subexpression_end dd ?
condition_stack dd ?
condition_stack_base dd ?
condition_stack_end dd ?
initial_parentheses dd ?
comparator dd ?
outer_expression dd ?
assembly_stack_base dd ?
assembly_stack_end dd ?
previous_symbol_end dd ?
further_whitespace dd ?
zero_digits dd ?
decimal_places dd ?
literal_exponent dd ?
update_function dd ?
argument_start dd ?
macro_parameters_context dd ?
new_local_namespace dd ?
file_name dd ?
string_end dd ?
message_end dd ?
data_area_symbol dd ?
data_area dd ?
data_offset dd ?
file_offset dq ?
data_length dd ?
local_path dd ?
error_line_start dd ?
error_line_end dd ?
error_symbol dd ?
last_source_entry dd ?
last_file_source_entry dd ?
preprocessed_text_end dd ?
source_text dd ?
source_text_length dd ?
tokenization_buffer dd ?
tokenization_buffer_length dd ?
buffer_end_offset dd ?
file_data dd ?
file_cache_pointer dd ?
address_length dd ?
data_unit_length dd ?
uninitialized_length dq ?
directive_block dd ?
number_of_iterations dd ?
number_of_parameters dd ?
number_of_values dd ?
parameter_index dd ?
value_index dd ?
value dd ?
value_length dd ?
metadata_length dd ?
sequence_header_cursor dd ?
sequence_header_length dd ?
expression_sequence_cursor dd ?
expression_sequence_end dd ?
context_boundary dd ?
whitespace_boundary dd ?
transforming_namespace dd ?
pattern_start dd ?
pattern_end dd ?
matched_context dd ?
substitutions_end dd ?
stored_position dd ?
stored_substitution dd ?
stored_context dd ?
stored_pattern dd ?
brackets dd ?
instruction_value dd ?
instruction_branch dd ?
instruction_body dd ?
number_of_lines dd ?
preprocessing_mode db ?
assembly_mode db ?
next_pass_needed db ?
shift_tracking db ?
name_kind db ?
name_volatile db ?
symbol_class db ?
symbol_required db ?
symbol_expected db ?
kept_symbol_flags db ?
chosen_class db ?
expected_class db ?
symbol_definition db ?
symbol_independent db ?
recognizer_setting db ?
label_independent db ?
value_type db ?
waiting_for_digit db ?
literal_exponent_sign db ?
literal_fractional_part db ?
float_literal_status db ?
use_raw_values db ?
last_token db ?
breakpoint_token db ?
current_constituent db ?
kept_value_in_workspace db ?
leave_opening_parentheses db ?
operator_argument_expected db ?
term_type db ?
bit_shift db ?
shift_overflow db ?
multiplier_sign db ?
high_bits_count db ?
first_sign db ?
second_sign db ?
comparator_priority db ?
result_type db ?
defined_element db ?
source_context_affected db ?
raw_value db ?
substitution_active db ?
stored_substitution_activity db ?
unprocessed_matching db ?
whitespace_matching db ?
macro_definition_active db ?
macro_flags db ?
macro_greedy db ?
calm_definition_active db ?
size_specified db ?
message_volatile db ?
displayed_byte db ?
alm_statement db ?
calm_result db ?
hidden_context db ?
contextless_processing db ?
variables_end:
trace_mode db ?

View File

@ -0,0 +1 @@
VERSION equ "kl0e"

View File

@ -0,0 +1,254 @@
match ,{
include 'win32a.inc'
include 'localptr.inc'
} match -,{
else
include 'selfhost.inc'
end match
_ equ }
format PE large NX DLL
entry DllEntryPoint
include '../../version.inc'
struct MEMORY_REGION
address dd ?
size dd ?
ends
section '.text' code executable
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'
DllEntryPoint:
mov eax,1
retn 12
fasmg_GetVersion:
mov eax,version_string
retn
fasmg_Assemble:
virtual at ebp - LOCAL_VARIABLES_SIZE
LocalVariables:
include '../../variables.inc'
maximum_number_of_passes dd ?
timestamp dq ?
systemtime SYSTEMTIME
filetime FILETIME
memory dd ?
systmp dd ?
rb (LocalVariables - $) and 11b
LOCAL_VARIABLES_SIZE = $ - LocalVariables
assert $ - ebp = 0
previous_frame dd ?
stored_edi dd ?
stored_esi dd ?
stored_ebx dd ?
return_address dd ?
FunctionParameters:
source_string dd ?
source_path dd ?
output_region dd ?
output_path dd ?
stdout dd ?
stderr dd ?
FUNCTION_PARAMETERS_SIZE = $ - FunctionParameters
end virtual
push ebx esi edi
enter LOCAL_VARIABLES_SIZE,0
call system_init
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1000
mov [maximum_depth_of_stack],10000
xor al,al
call assembly_init
assemble:
mov esi,[source_string]
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
call assembly_shutdown
call system_shutdown
mov eax,-2
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
mov esi,[output_region]
test esi,esi
jz output_copied
call get_output_length
test edx,edx
jnz out_of_memory
mov [value_length],eax
xchg eax,[esi+MEMORY_REGION.size]
cmp [esi+MEMORY_REGION.address],0
je new_region_for_output
cmp eax,[value_length]
jae copy_output
invoke VirtualAlloc,[esi+MEMORY_REGION.address],[esi+MEMORY_REGION.size],MEM_COMMIT,PAGE_READWRITE
test eax,eax
jnz copy_output
invoke VirtualFree,[esi+MEMORY_REGION.address],0,MEM_RELEASE
new_region_for_output:
invoke VirtualAlloc,0,[esi+MEMORY_REGION.size],MEM_COMMIT,PAGE_READWRITE
test eax,eax
jz out_of_memory
mov [esi+MEMORY_REGION.address],eax
copy_output:
mov edi,[esi+MEMORY_REGION.address]
xor eax,eax
mov dword [file_offset],eax
mov dword [file_offset+4],eax
call read_from_output
output_copied:
mov ebx,[source_path]
mov edi,[output_path]
mov eax,ebx
or eax,edi
jz output_written
call write_output_file
jc write_failed
output_written:
call assembly_shutdown
call system_shutdown
xor eax,eax
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
assembly_failed:
mov eax,[first_error]
xor ecx,ecx
count_errors:
inc ecx
mov eax,[eax+Error.next]
test eax,eax
jnz count_errors
push ecx
call show_errors
call assembly_shutdown
call system_shutdown
pop eax
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
write_failed:
call assembly_shutdown
call system_shutdown
mov eax,-3
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
out_of_memory:
call assembly_shutdown
call system_shutdown
mov eax,-1
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
include 'system.inc'
section '.rdata' data readable
data import
library kernel32,'KERNEL32.DLL'
import kernel32,\
CloseHandle,'CloseHandle',\
CreateFile,'CreateFileA',\
ExitProcess,'ExitProcess',\
GetCommandLine,'GetCommandLineA',\
GetEnvironmentVariable,'GetEnvironmentVariableA',\
GetStdHandle,'GetStdHandle',\
GetSystemTime,'GetSystemTime',\
GetTickCount,'GetTickCount',\
HeapAlloc,'HeapAlloc',\
HeapCreate,'HeapCreate',\
HeapDestroy,'HeapDestroy',\
HeapFree,'HeapFree',\
HeapReAlloc,'HeapReAlloc',\
HeapSize,'HeapSize',\
VirtualAlloc,'VirtualAlloc',\
VirtualFree,'VirtualFree',\
ReadFile,'ReadFile',\
SetFilePointer,'SetFilePointer',\
SystemTimeToFileTime,'SystemTimeToFileTime',\
WriteFile,'WriteFile',\
GetLastError,'GetLastError'
end data
align 4
data export
export 'FASMG.DLL',\
fasmg_GetVersion,'fasmg_GetVersion',\
fasmg_Assemble,'fasmg_Assemble'
end data
include '../../tables.inc'
include '../../messages.inc'
version_string db VERSION,0
section '.reloc' fixups data readable discardable

View File

@ -0,0 +1,28 @@
macro pushd arg
{
if arg eqtype +ebp & arg relativeto ebp
if arg - ebp
push eax
lea eax,[arg]
xchg eax,[esp]
else
push ebp
end if
else if ~ arg eq
pushd arg
end if
}
macro mov dest,src
{
if src eqtype +ebp & src relativeto ebp
if src - ebp
lea dest,[src]
else
mov dest,ebp
end if
else
mov dest,src
end if
}

View File

@ -0,0 +1,266 @@
include '../../../examples/x86/include/80386.inc'
macro format?.PE? settings
PE.Settings.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE or IMAGE_FILE_LINE_NUMS_STRIPPED or IMAGE_FILE_LOCAL_SYMS_STRIPPED
PE.Settings.DllCharacteristics = 0
PE.Settings.Stamp = +VERSION
PE.Settings.LegacyHeaders = 0
local seq
define seq settings:
while 1
match :, seq
break
else match =DLL? more, seq
PE.Settings.Characteristics = PE.Settings.Characteristics or IMAGE_FILE_DLL
redefine seq more
else match =large? more, seq
PE.Settings.Characteristics = PE.Settings.Characteristics or IMAGE_FILE_LARGE_ADDRESS_AWARE
redefine seq more
else match =WDM? more, seq
PE.Settings.DllCharacteristics = PE.Settings.DllCharacteristics or IMAGE_DLLCHARACTERISTICS_WDM_DRIVER
redefine seq more
else match =NX? more, seq
PE.Settings.DllCharacteristics = PE.Settings.DllCharacteristics or IMAGE_DLLCHARACTERISTICS_NX_COMPAT
redefine seq more
else match =at? base =on? stub :, seq
PE.Settings.ImageBase = base
PE.Settings.Stub = stub
break
else match =at? base :, seq
PE.Settings.ImageBase = base
break
else match =on? stub :, seq
PE.Settings.Stub = stub
break
else
match =GUI? more, seq
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
redefine seq more
else match =console? more, seq
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
redefine seq more
else match =native? more, seq
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_NATIVE
PE.Settings.SectionAlignment = 32
PE.Settings.FileAlignment = 32
redefine seq more
else match =EFI? more, seq
PE.Settings.Magic = 0x20B
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION
redefine seq more
else match =EFIboot? more, seq
PE.Settings.Magic = 0x20B
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
redefine seq more
else match =EFIruntime? more, seq
PE.Settings.Magic = 0x20B
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
redefine seq more
else
err 'invalid argument'
break
end match
match V.v more, seq
PE.Settings.MajorSubsystemVersion = V
PE.Settings.MinorSubsystemVersion = v
redefine seq more
end match
end match
end while
if PE.Settings.Characteristics and IMAGE_FILE_DLL
format binary as 'dll'
else
format binary as 'exe'
end if
include '../../../examples/x86/include/format/pe.inc'
use32
end macro
macro struct? name
macro ends?!
end namespace
esc end struc
virtual at 0
name name
sizeof.name = $
end virtual
purge ends?
end macro
esc struc name
label . : sizeof.name
namespace .
end macro
calminstruction invoke? proc*,args&
local tmp, tmpst, stack
match , args
jyes go
collect:
match tmpst=,args, args
take stack, tmpst
jyes collect
push:
match tmp], args
jyes regular
check args relativeto ebp & args - ebp
jno regular
arrange tmp, =push =eax
assemble tmp
arrange tmp, =lea =eax,[args]
assemble tmp
arrange tmp, =xchg =eax,[=esp]
assemble tmp
jump next
regular:
arrange tmp, =pushd args
assemble tmp
next:
take args, stack
jyes push
go:
arrange tmp, =call [proc]
assemble tmp
end calminstruction
calminstruction mov? dest*,src*
local tmp
match tmp], src
jyes regular
check src relativeto ebp & src - ebp
jno regular
arrange tmp, =lea dest,[src]
assemble tmp
exit
regular:
arrange tmp, =mov dest,src
assemble tmp
end calminstruction
macro library? definitions&
PE.Imports:
iterate <name,string>, definitions
if ~ name.redundant
dd RVA name.lookup,0,0,RVA name.str,RVA name.address
end if
name.referred = 1
end iterate
dd 0,0,0,0,0
iterate <name,string>, definitions
if ~ name.redundant
name.str db string,0
align 2
end if
end iterate
end macro
macro import? name,definitions&
align 4
if defined name.referred
name.lookup:
iterate <label,string>, definitions
if used label
if string eqtype ''
dd RVA name.label
else
dd 80000000h + string
end if
end if
end iterate
if $ > name.lookup
name.redundant = 0
dd 0
else
name.redundant = 1
end if
name.address:
iterate <label,string>, definitions
if used label
if string eqtype ''
label dd RVA name.label
else
label dd 80000000h + string
end if
end if
end iterate
if ~ name.redundant
dd 0
end if
iterate <label,string>, definitions
if used label & string eqtype ''
name.label dw 0
db string,0
align 2
end if
end iterate
end if
end macro
macro export dllname,exports&
iterate <label,string>, exports
local module,addresses,names,ordinal,count
count = %%
dd 0,0,0,RVA module,1
dd count,count,RVA addresses,RVA names,RVA ordinal
addresses:
repeat count
indx %
dd RVA label
end repeat
names:
repeat count
dd RVA names.name#%
end repeat
ordinal:
repeat count
dw %-1
end repeat
module db dllname,0
repeat count
indx %
names.name#% db string,0
end repeat
local x,y,z,str1,str2,v1,v2
x = count shr 1
while x > 0
y = x
while y < count
z = y
while z-x >= 0
load v1:dword from names+z*4
str1 = ($-(RVA $))+v1
load v2:dword from names+(z-x)*4
str2 = ($-(RVA $))+v2
while v1 > 0
load v1:byte from str1+%-1
load v2:byte from str2+%-1
if v1 <> v2
break
end if
end while
if v1 < v2
load v1:dword from names+z*4
load v2:dword from names+(z-x)*4
store v1:dword at names+(z-x)*4
store v2:dword at names+z*4
load v1:word from ordinal+z*2
load v2:word from ordinal+(z-x)*2
store v1:word at ordinal+(z-x)*2
store v2:word at ordinal+z*2
else
break
end if
z = z-x
end while
y = y+1
end while
x = x shr 1
end while
break
end iterate
end macro
include '../kernel32.inc'

View File

@ -0,0 +1,214 @@
LINE_FEED equ 13,10
system_init:
invoke HeapCreate,0,20000h,0
mov [memory],eax
test eax,eax
jz out_of_memory
invoke GetSystemTime,systemtime
invoke SystemTimeToFileTime,systemtime,filetime
mov ebx,[filetime.dwLowDateTime]
mov eax,[filetime.dwHighDateTime]
sub ebx,116444736000000000 and 0FFFFFFFFh
sbb eax,116444736000000000 shr 32
xor edx,edx
mov ecx,10000000
div ecx
mov dword [timestamp+4],eax
mov eax,ebx
div ecx
mov dword [timestamp],eax
retn
system_shutdown:
cmp [memory],0
je memory_released
invoke HeapDestroy,[memory]
memory_released:
retn
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
; note:
; use of malloc_fixed hints that block will be kept as is until the end of assembly
; use of malloc_growable hints that block is likely to be resized
invoke HeapAlloc,[memory],0,ecx
test eax,eax
jz out_of_memory
memory_allocated:
push eax
invoke HeapSize,[memory],0,eax
mov ecx,eax
pop eax
cmp ecx,-1
je out_of_memory
retn
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
invoke HeapReAlloc,[memory],0,eax,ecx
test eax,eax
jnz memory_allocated
jmp out_of_memory
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz interface_error
cmp eax,-1
je interface_error
invoke HeapFree,[memory],0,eax
test eax,eax
jz interface_error
clc
retn
interface_error:
stc
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
invoke CreateFile,edx,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0
cmp eax,-1
je interface_error
mov ebx,eax
clc
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
invoke CreateFile,edx,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0
cmp eax,-1
je interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke WriteFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke ReadFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
invoke CloseHandle,ebx
retn
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
movzx ecx,cl
mov [systmp],edx
invoke SetFilePointer,ebx,eax,systmp,ecx
cmp eax,-1
jne lseek_ok
invoke GetLastError
test eax,eax
jnz interface_error
not eax
lseek_ok:
mov edx,[systmp]
clc
retn
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,[stdout]
jmp write_string
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,[stderr]
write_string:
test ebx,ebx
jz hidden_display
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
mov edx,esi
write_portion_to_stdout:
mov eax,51200
cmp ecx,eax
jbe final_write_to_stdout
sub ecx,eax
add eax,edx
push eax ecx
invoke WriteFile,ebx,edx,51200,systmp,0
pop ecx edx
jmp write_portion_to_stdout
final_write_to_stdout:
invoke WriteFile,ebx,edx,ecx,systmp,0
hidden_display:
pop ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ecx
invoke GetEnvironmentVariable,esi,edi,ecx
pop ecx
cmp eax,ecx
jae environment_variable_ready
mov byte [edi+eax],0
environment_variable_ready:
inc eax
retn

View File

@ -0,0 +1,529 @@
match ,{
include 'win32a.inc'
} match -,{
else
include 'selfhost.inc'
end match
_ equ }
format PE large NX console 4.0
entry start
include '../version.inc'
section '.text' code executable
include 'system.inc'
start:
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
movzx ecx,[verbosity_level]
jecxz init
or al,TRACE_ERROR_STACK
dec ecx
jz init
or al,TRACE_DISPLAY
init:
call assembly_init
invoke GetTickCount
mov [timer],eax
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
invoke GetTickCount
sub eax,[timer]
xor edx,edx
add eax,50
mov ecx,1000
div ecx
mov ebx,eax
mov eax,edx
xor edx,edx
mov ecx,100
div ecx
mov [timer],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,[timer]
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
invoke ExitProcess,0
assembly_failed:
call show_errors
call assembly_shutdown
call system_shutdown
invoke ExitProcess,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
invoke ExitProcess,3
display_usage_information:
mov esi,_usage
xor ecx,ecx
call display_string
call system_shutdown
invoke ExitProcess,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],al
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1
mov [maximum_depth_of_stack],10000
invoke GetCommandLine
mov esi,eax
mov edi,eax
or ecx,-1
xor al,al
repne scasb
sub edi,esi
mov ecx,edi
call malloc
mov edi,eax
get_argument:
xor ah,ah
read_character:
lodsb
test al,al
jz no_more_arguments
cmp al,22h
je switch_quote
cmp ax,20h
je end_argument
stosb
jmp read_character
end_argument:
xor al,al
stosb
find_next_argument:
mov al,[esi]
test al,al
jz no_more_arguments
cmp al,20h
jne next_argument_found
inc esi
jmp find_next_argument
switch_quote:
xor ah,1
jmp read_character
next_argument_found:
cmp al,'-'
je get_option
cmp al,'/'
je get_option
cmp [source_path],0
je get_source_path
cmp [output_path],0
je get_output_path
error_in_arguments:
or al,-1
retn
get_source_path:
mov [source_path],edi
jmp get_argument
get_output_path:
mov [output_path],edi
jmp get_argument
no_more_arguments:
cmp [source_path],0
je error_in_arguments
xor al,al
stosb
retn
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
mov al,[esi]
cmp al,20h
je find_next_argument
test al,al
jnz error_in_arguments
jmp find_next_argument
set_verbose_mode:
call get_option_value
jc error_in_arguments
cmp edx,2
ja error_in_arguments
mov [verbosity_level],dl
jmp find_next_argument
set_errors_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_number_of_errors],edx
jmp find_next_argument
set_recursion_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_depth_of_stack],edx
jmp find_next_argument
set_passes_limit:
call get_option_value
jc error_in_arguments
test edx,edx
jz error_in_arguments
mov [maximum_number_of_passes],edx
jmp find_next_argument
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
cmp al,20h
je option_value_ok
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:
push edi
find_command_segment:
cmp byte [esi],20h
jne command_segment_found
inc esi
jmp find_command_segment
command_segment_found:
xor ah,ah
cmp byte [esi],22h
jne measure_command_segment
inc esi
inc ah
measure_command_segment:
mov ebx,esi
scan_command_segment:
mov ecx,esi
mov al,[esi]
test al,al
jz command_segment_measured
cmp ax,20h
je command_segment_measured
cmp ax,22h
je command_segment_measured
inc esi
cmp al,22h
jne scan_command_segment
command_segment_measured:
sub ecx,ebx
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:
xchg esi,ebx
rep movsb
mov esi,ebx
sub edi,[initial_commands]
mov [initial_commands_length],edi
mov al,[esi]
test al,al
jz initial_command_ready
cmp al,20h
jne command_segment_found
initial_command_ready:
mov edi,[initial_commands]
add edi,[initial_commands_length]
mov ax,0Ah
stosw
inc [initial_commands_length]
pop edi
jmp find_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 '../symbols.inc'
include '../assembler.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 '.bss' readable writeable
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 ?
stdout dd ?
stderr dd ?
memory dd ?
timestamp dq ?
systemtime SYSTEMTIME
filetime FILETIME
systmp dd ?
timer dd ?
verbosity_level db ?
no_logo db ?
section '.rdata' data readable
data import
library kernel32,'KERNEL32.DLL'
import kernel32,\
CloseHandle,'CloseHandle',\
CreateFile,'CreateFileA',\
ExitProcess,'ExitProcess',\
GetCommandLine,'GetCommandLineA',\
GetEnvironmentVariable,'GetEnvironmentVariableA',\
GetStdHandle,'GetStdHandle',\
GetSystemTime,'GetSystemTime',\
GetTickCount,'GetTickCount',\
HeapAlloc,'HeapAlloc',\
HeapCreate,'HeapCreate',\
HeapDestroy,'HeapDestroy',\
HeapFree,'HeapFree',\
HeapReAlloc,'HeapReAlloc',\
HeapSize,'HeapSize',\
ReadFile,'ReadFile',\
SetFilePointer,'SetFilePointer',\
SystemTimeToFileTime,'SystemTimeToFileTime',\
WriteFile,'WriteFile',\
GetLastError,'GetLastError'
end data
_logo db 'flat assembler version g.',VERSION,13,10,0
_usage db 'Usage: fasmg source [output]',13,10
db 'Optional settings:',13,10
db ' -e limit Set the maximum number of displayed errors (default 1)',13,10
db ' -p limit Set the maximum allowed number of passes (default 100)',13,10
db ' -r limit Set the maximum depth of the stack (default 10000)',13,10
db ' -v flag Enable or disable showing all lines from the stack (default 0)',13,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
include '../tables.inc'
include '../messages.inc'

View File

@ -0,0 +1,96 @@
struct FILETIME
dwLowDateTime dd ?
dwHighDateTime dd ?
ends
struct SYSTEMTIME
wYear dw ?
wMonth dw ?
wDayOfWeek dw ?
wDay dw ?
wHour dw ?
wMinute dw ?
wSecond dw ?
wMilliseconds dw ?
ends
; Page access flags
PAGE_NOACCESS = 001h
PAGE_READONLY = 002h
PAGE_READWRITE = 004h
PAGE_WRITECOPY = 008h
PAGE_EXECUTE = 010h
PAGE_EXECUTE_READ = 020h
PAGE_EXECUTE_READWRITE = 040h
PAGE_EXECUTE_WRITECOPY = 080h
PAGE_GUARD = 100h
PAGE_NOCACHE = 200h
; Memory allocation flags
MEM_COMMIT = 001000h
MEM_RESERVE = 002000h
MEM_DECOMMIT = 004000h
MEM_RELEASE = 008000h
MEM_FREE = 010000h
MEM_PRIVATE = 020000h
MEM_MAPPED = 040000h
MEM_RESET = 080000h
MEM_TOP_DOWN = 100000h
; Heap allocation flags
HEAP_NO_SERIALIZE = 1
HEAP_GENERATE_EXCEPTIONS = 4
HEAP_ZERO_MEMORY = 8
; Device handles
INVALID_HANDLE_VALUE = -1
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
; Access rights
DELETE_RIGHT = 00010000h
READ_CONTROL = 00020000h
WRITE_DAC = 00040000h
WRITE_OWNER = 00080000h
SYNCHRONIZE = 00100000h
STANDARD_RIGHTS_READ = READ_CONTROL
STANDARD_RIGHTS_WRITE = READ_CONTROL
STANDARD_RIGHTS_EXECUTE = READ_CONTROL
STANDARD_RIGHTS_REQUIRED = 000F0000h
STANDARD_RIGHTS_ALL = 001F0000h
SPECIFIC_RIGHTS_ALL = 0000FFFFh
ACCESS_SYSTEM_SECURITY = 01000000h
MAXIMUM_ALLOWED = 02000000h
GENERIC_READ = 80000000h
GENERIC_WRITE = 40000000h
GENERIC_EXECUTE = 20000000h
GENERIC_ALL = 10000000h
PROCESS_TERMINATE = 00000001h
PROCESS_CREATE_THREAD = 00000002h
PROCESS_VM_OPERATION = 00000008h
PROCESS_VM_READ = 00000010h
PROCESS_VM_WRITE = 00000020h
PROCESS_DUP_HANDLE = 00000040h
PROCESS_CREATE_PROCESS = 00000080h
PROCESS_SET_QUOTA = 00000100h
PROCESS_SET_INFORMATION = 00000200h
PROCESS_QUERY_INFORMATION = 00000400h
PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or 0FFFh
FILE_SHARE_READ = 00000001h
FILE_SHARE_WRITE = 00000002h
FILE_SHARE_DELETE = 00000004h
; CreateFile actions
CREATE_NEW = 1
CREATE_ALWAYS = 2
OPEN_EXISTING = 3
OPEN_ALWAYS = 4
TRUNCATE_EXISTING = 5

View File

@ -0,0 +1,171 @@
include '../../examples/x86/include/80386.inc'
macro format?.PE? settings
PE.Settings.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE or IMAGE_FILE_LINE_NUMS_STRIPPED or IMAGE_FILE_LOCAL_SYMS_STRIPPED
PE.Settings.DllCharacteristics = 0
PE.Settings.Stamp = +VERSION
local seq
define seq settings:
while 1
match :, seq
break
else match =DLL? more, seq
PE.Settings.Characteristics = PE.Settings.Characteristics or IMAGE_FILE_DLL
redefine seq more
else match =large? more, seq
PE.Settings.Characteristics = PE.Settings.Characteristics or IMAGE_FILE_LARGE_ADDRESS_AWARE
redefine seq more
else match =WDM? more, seq
PE.Settings.DllCharacteristics = PE.Settings.DllCharacteristics or IMAGE_DLLCHARACTERISTICS_WDM_DRIVER
redefine seq more
else match =NX? more, seq
PE.Settings.DllCharacteristics = PE.Settings.DllCharacteristics or IMAGE_DLLCHARACTERISTICS_NX_COMPAT
redefine seq more
else match =at? base =on? stub :, seq
PE.Settings.ImageBase = base
PE.Settings.Stub = stub
break
else match =at? base :, seq
PE.Settings.ImageBase = base
break
else match =on? stub :, seq
PE.Settings.Stub = stub
break
else
match =GUI? more, seq
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
redefine seq more
else match =console? more, seq
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
redefine seq more
else match =native? more, seq
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_NATIVE
PE.Settings.SectionAlignment = 32
PE.Settings.FileAlignment = 32
redefine seq more
else match =EFI? more, seq
PE.Settings.Magic = 0x20B
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION
redefine seq more
else match =EFIboot? more, seq
PE.Settings.Magic = 0x20B
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
redefine seq more
else match =EFIruntime? more, seq
PE.Settings.Magic = 0x20B
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
redefine seq more
else
err 'invalid argument'
break
end match
match V.v more, seq
PE.Settings.MajorSubsystemVersion = V
PE.Settings.MinorSubsystemVersion = v
redefine seq more
end match
end match
end while
if PE.Settings.Characteristics and IMAGE_FILE_DLL
format binary as 'dll'
else
format binary as 'exe'
end if
include '../../examples/x86/include/format/pe.inc'
use32
end macro
macro struct? name
macro ends?!
end namespace
esc end struc
virtual at 0
name name
sizeof.name = $
end virtual
purge ends?
end macro
esc struc name
label . : sizeof.name
namespace .
end macro
calminstruction invoke? proc*,args&
local tmp, stack
match , args
jyes go
collect:
match tmp=,args, args
take stack, tmp
jyes collect
push:
arrange args, =pushd args
assemble args
take args, stack
jyes push
go:
arrange proc, =call [proc]
assemble proc
end calminstruction
macro library? definitions&
PE.Imports:
iterate <name,string>, definitions
if ~ name.redundant
dd RVA name.lookup,0,0,RVA name.str,RVA name.address
end if
name.referred = 1
end iterate
dd 0,0,0,0,0
iterate <name,string>, definitions
if ~ name.redundant
name.str db string,0
align 2
end if
end iterate
end macro
macro import? name,definitions&
align 4
if defined name.referred
name.lookup:
iterate <label,string>, definitions
if used label
if string eqtype ''
dd RVA name.label
else
dd 80000000h + string
end if
end if
end iterate
if $ > name.lookup
name.redundant = 0
dd 0
else
name.redundant = 1
end if
name.address:
iterate <label,string>, definitions
if used label
if string eqtype ''
label dd RVA name.label
else
label dd 80000000h + string
end if
end if
end iterate
if ~ name.redundant
dd 0
end if
iterate <label,string>, definitions
if used label & string eqtype ''
name.label dw 0
db string,0
align 2
end if
end iterate
end if
end macro
include 'kernel32.inc'

View File

@ -0,0 +1,218 @@
LINE_FEED equ 13,10
system_init:
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov [stdout],eax
invoke GetStdHandle,STD_ERROR_HANDLE
mov [stderr],eax
invoke HeapCreate,0,20000h,0
mov [memory],eax
test eax,eax
jz out_of_memory
invoke GetSystemTime,systemtime
invoke SystemTimeToFileTime,systemtime,filetime
mov ebx,[filetime.dwLowDateTime]
mov eax,[filetime.dwHighDateTime]
sub ebx,116444736000000000 and 0FFFFFFFFh
sbb eax,116444736000000000 shr 32
xor edx,edx
mov ecx,10000000
div ecx
mov dword [timestamp+4],eax
mov eax,ebx
div ecx
mov dword [timestamp],eax
retn
system_shutdown:
cmp [memory],0
je memory_released
invoke HeapDestroy,[memory]
memory_released:
invoke CloseHandle,[stdout]
invoke CloseHandle,[stderr]
retn
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
; note:
; use of malloc_fixed hints that block will be kept as is until the end of assembly
; use of malloc_growable hints that block is likely to be resized
invoke HeapAlloc,[memory],0,ecx
test eax,eax
jz out_of_memory
memory_allocated:
push eax
invoke HeapSize,[memory],0,eax
mov ecx,eax
pop eax
cmp ecx,-1
je out_of_memory
retn
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
invoke HeapReAlloc,[memory],0,eax,ecx
test eax,eax
jnz memory_allocated
jmp out_of_memory
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz interface_error
cmp eax,-1
je interface_error
invoke HeapFree,[memory],0,eax
test eax,eax
jz interface_error
clc
retn
interface_error:
stc
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
invoke CreateFile,edx,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0
cmp eax,-1
je interface_error
mov ebx,eax
clc
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
invoke CreateFile,edx,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0
cmp eax,-1
je interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke WriteFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke ReadFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
invoke CloseHandle,ebx
retn
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
movzx ecx,cl
mov [systmp],edx
invoke SetFilePointer,ebx,eax,systmp,ecx
cmp eax,-1
jne lseek_ok
invoke GetLastError
test eax,eax
jnz interface_error
not eax
lseek_ok:
mov edx,[systmp]
clc
retn
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,[stdout]
jmp write_string
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,[stderr]
write_string:
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
mov edx,esi
write_portion_to_stdout:
mov eax,51200
cmp ecx,eax
jbe final_write_to_stdout
sub ecx,eax
add eax,edx
push eax ecx
invoke WriteFile,ebx,edx,51200,systmp,0
pop ecx edx
jmp write_portion_to_stdout
final_write_to_stdout:
invoke WriteFile,ebx,edx,ecx,systmp,0
pop ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ecx
invoke GetEnvironmentVariable,esi,edi,ecx
pop ecx
cmp eax,ecx
jae environment_variable_ready
mov byte [edi+eax],0
environment_variable_ready:
inc eax
retn