asm_dip/toolchain/fasmg.kl0e/source/output.inc
2024-11-24 23:13:28 -05:00

884 lines
22 KiB
PHP

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