884 lines
22 KiB
PHP
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
|