; flat assembler core ; Copyright (c) 1999-2022, Tomasz Grysztar. ; All rights reserved. calculate_expression: mov [current_offset],edi mov [value_undefined],0 cmp byte [esi],0 je get_string_value cmp byte [esi],'.' je convert_fp calculation_loop: mov eax,[tagged_blocks] sub eax,0Ch cmp eax,edi jbe out_of_memory lods byte [esi] cmp al,1 je get_byte_number cmp al,2 je get_word_number cmp al,4 je get_dword_number cmp al,8 je get_qword_number cmp al,0Fh je value_out_of_range cmp al,10h je get_register cmp al,11h je get_label cmp al,')' je expression_calculated cmp al,']' je expression_calculated cmp al,'!' je invalid_expression sub edi,14h mov ebx,edi sub ebx,14h cmp al,0F0h je calculate_rva cmp al,0F1h je calculate_plt cmp al,0D0h je calculate_not cmp al,0E0h je calculate_bsf cmp al,0E1h je calculate_bsr cmp al,083h je calculate_neg mov dx,[ebx+8] or dx,[edi+8] cmp al,80h je calculate_add cmp al,81h je calculate_sub mov ah,[ebx+12] or ah,[edi+12] jz absolute_values_calculation call recoverable_misuse absolute_values_calculation: cmp al,90h je calculate_mul cmp al,91h je calculate_div or dx,dx jnz invalid_expression cmp al,0A0h je calculate_mod cmp al,0B0h je calculate_and cmp al,0B1h je calculate_or cmp al,0B2h je calculate_xor cmp al,0C0h je calculate_shl cmp al,0C1h je calculate_shr jmp invalid_expression expression_calculated: sub edi,14h cmp [value_undefined],0 je expression_value_ok xor eax,eax mov [edi],eax mov [edi+4],eax mov [edi+12],eax expression_value_ok: ret get_byte_number: xor eax,eax lods byte [esi] stos dword [edi] xor al,al stos dword [edi] got_number: and word [edi-8+8],0 and word [edi-8+12],0 and dword [edi-8+16],0 add edi,0Ch jmp calculation_loop get_word_number: xor eax,eax lods word [esi] stos dword [edi] xor ax,ax stos dword [edi] jmp got_number get_dword_number: movs dword [edi],[esi] xor eax,eax stos dword [edi] jmp got_number get_qword_number: movs dword [edi],[esi] movs dword [edi],[esi] jmp got_number get_register: mov byte [edi+9],0 and word [edi+12],0 lods byte [esi] mov [edi+8],al mov byte [edi+10],1 xor eax,eax mov [edi+16],eax stos dword [edi] stos dword [edi] add edi,0Ch jmp calculation_loop get_label: xor eax,eax mov [edi+8],eax mov [edi+12],eax mov [edi+20],eax lods dword [esi] cmp eax,0Fh jb predefined_label je reserved_word_used_as_symbol mov ebx,eax mov ax,[current_pass] mov [ebx+18],ax mov cl,[ebx+9] shr cl,1 and cl,1 neg cl or byte [ebx+8],8 test byte [ebx+8],1 jz label_undefined cmp ax,[ebx+16] je unadjusted_label test byte [ebx+8],4 jnz label_out_of_scope test byte [ebx+9],1 jz unadjusted_label mov eax,[ebx] sub eax,dword [adjustment] stos dword [edi] mov eax,[ebx+4] sbb eax,dword [adjustment+4] stos dword [edi] sbb cl,[adjustment_sign] mov [edi-8+13],cl mov eax,dword [adjustment] or al,[adjustment_sign] or eax,dword [adjustment+4] jz got_label or [next_pass_needed],-1 jmp got_label unadjusted_label: mov eax,[ebx] stos dword [edi] mov eax,[ebx+4] stos dword [edi] mov [edi-8+13],cl got_label: test byte [ebx+9],4 jnz invalid_use_of_symbol call store_label_reference mov al,[ebx+11] mov [edi-8+12],al mov eax,[ebx+12] mov [edi-8+8],eax cmp al,ah jne labeled_registers_ok shr eax,16 add al,ah jo labeled_registers_ok xor ah,ah mov [edi-8+10],ax mov [edi-8+9],ah labeled_registers_ok: mov eax,[ebx+20] mov [edi-8+16],eax add edi,0Ch mov al,[ebx+10] or al,al jz calculation_loop test [operand_flags],1 jnz calculation_loop check_size: xchg [operand_size],al or al,al jz calculation_loop cmp al,[operand_size] jne operand_sizes_do_not_match jmp calculation_loop actual_file_offset_label: mov eax,[undefined_data_end] mov ebp,[addressing_space] test byte [ds:ebp+0Ah],1 jnz use_undefined_data_offset cmp eax,[current_offset] jne use_current_offset use_undefined_data_offset: mov eax,[undefined_data_start] jmp make_file_offset_label current_file_offset_label: mov ebp,[addressing_space] test byte [ds:ebp+0Ah],1 jz use_current_offset mov eax,[undefined_data_end] jmp make_file_offset_label use_current_offset: mov eax,[current_offset] make_file_offset_label: cmp [output_format],2 jae invalid_use_of_symbol sub eax,[code_start] jmp make_dword_label_value current_offset_label: mov eax,[current_offset] make_current_offset_label: xor edx,edx xor ch,ch mov ebp,[addressing_space] sub eax,[ds:ebp] sbb edx,[ds:ebp+4] sbb ch,[ds:ebp+8] jp current_offset_label_ok call recoverable_overflow current_offset_label_ok: stos dword [edi] mov eax,edx stos dword [edi] mov eax,[ds:ebp+10h] stos dword [edi] mov cl,[ds:ebp+9] mov [edi-12+12],cx mov eax,[ds:ebp+14h] mov [edi-12+16],eax add edi,8 jmp calculation_loop org_origin_label: mov eax,[addressing_space] mov eax,[eax+18h] jmp make_current_offset_label counter_label: mov eax,[counter] make_dword_label_value: stos dword [edi] xor eax,eax stos dword [edi] add edi,0Ch jmp calculation_loop timestamp_label: call make_timestamp make_qword_label_value: stos dword [edi] mov eax,edx stos dword [edi] add edi,0Ch jmp calculation_loop predefined_label: or eax,eax jz current_offset_label cmp eax,1 je counter_label cmp eax,2 je timestamp_label cmp eax,3 je org_origin_label cmp eax,4 je current_file_offset_label cmp eax,5 je actual_file_offset_label mov edx,invalid_value jmp error_undefined label_out_of_scope: mov edx,symbol_out_of_scope jmp error_undefined label_undefined: mov edx,undefined_symbol error_undefined: cmp [current_pass],1 ja undefined_value force_next_pass: or [next_pass_needed],-1 undefined_value: or [value_undefined],-1 and word [edi+12],0 xor eax,eax stos dword [edi] stos dword [edi] add edi,0Ch cmp [error_line],0 jne calculation_loop mov eax,[current_line] mov [error_line],eax mov [error],edx mov [error_info],ebx jmp calculation_loop calculate_add: xor ah,ah mov ah,[ebx+12] mov al,[edi+12] or al,al jz add_values or ah,ah jz add_relocatable add ah,al jnz invalid_add mov ecx,[edi+16] cmp ecx,[ebx+16] je add_values invalid_add: call recoverable_misuse jmp add_values add_relocatable: mov ah,al mov ecx,[edi+16] mov [ebx+16],ecx add_values: mov [ebx+12],ah mov eax,[edi] add [ebx],eax mov eax,[edi+4] adc [ebx+4],eax mov al,[edi+13] adc [ebx+13],al jp add_sign_ok call recoverable_overflow add_sign_ok: or dx,dx jz calculation_loop push esi mov esi,ebx mov cl,[edi+10] mov al,[edi+8] call add_register mov cl,[edi+11] mov al,[edi+9] call add_register pop esi jmp calculation_loop add_register: or al,al jz add_register_done add_register_start: cmp [esi+8],al jne add_in_second_slot add [esi+10],cl jo value_out_of_range jnz add_register_done mov byte [esi+8],0 ret add_in_second_slot: cmp [esi+9],al jne create_in_first_slot add [esi+11],cl jo value_out_of_range jnz add_register_done mov byte [esi+9],0 ret create_in_first_slot: cmp byte [esi+8],0 jne create_in_second_slot mov [esi+8],al mov [esi+10],cl ret create_in_second_slot: cmp byte [esi+9],0 jne invalid_expression mov [esi+9],al mov [esi+11],cl add_register_done: ret out_of_range: jmp calculation_loop calculate_sub: xor ah,ah mov ah,[ebx+12] mov al,[edi+12] or al,al jz sub_values or ah,ah jz negate_relocatable cmp al,ah jne invalid_sub xor ah,ah mov ecx,[edi+16] cmp ecx,[ebx+16] je sub_values invalid_sub: call recoverable_misuse jmp sub_values negate_relocatable: neg al mov ah,al mov ecx,[edi+16] mov [ebx+16],ecx sub_values: mov [ebx+12],ah mov eax,[edi] sub [ebx],eax mov eax,[edi+4] sbb [ebx+4],eax mov al,[edi+13] sbb [ebx+13],al jp sub_sign_ok cmp [error_line],0 jne sub_sign_ok call recoverable_overflow sub_sign_ok: or dx,dx jz calculation_loop push esi mov esi,ebx mov cl,[edi+10] mov al,[edi+8] call sub_register mov cl,[edi+11] mov al,[edi+9] call sub_register pop esi jmp calculation_loop sub_register: or al,al jz add_register_done neg cl jo value_out_of_range jmp add_register_start calculate_mul: or dx,dx jz mul_start cmp word [ebx+8],0 jne mul_start xor ecx,ecx swap_values: mov eax,[ebx+ecx] xchg eax,[edi+ecx] mov [ebx+ecx],eax add ecx,4 cmp ecx,16 jb swap_values mul_start: push esi edx mov esi,ebx xor bl,bl cmp byte [esi+13],0 je mul_first_sign_ok xor bl,-1 mov eax,[esi] mov edx,[esi+4] not eax not edx add eax,1 adc edx,0 mov [esi],eax mov [esi+4],edx or eax,edx jz mul_overflow mul_first_sign_ok: cmp byte [edi+13],0 je mul_second_sign_ok xor bl,-1 cmp byte [esi+8],0 je mul_first_register_sign_ok neg byte [esi+10] jo invalid_expression mul_first_register_sign_ok: cmp byte [esi+9],0 je mul_second_register_sign_ok neg byte [esi+11] jo invalid_expression mul_second_register_sign_ok: mov eax,[edi] mov edx,[edi+4] not eax not edx add eax,1 adc edx,0 mov [edi],eax mov [edi+4],edx or eax,edx jz mul_overflow mul_second_sign_ok: cmp dword [esi+4],0 jz mul_numbers cmp dword [edi+4],0 jz mul_numbers jnz mul_overflow mul_numbers: mov eax,[esi+4] mul dword [edi] or edx,edx jnz mul_overflow mov ecx,eax mov eax,[esi] mul dword [edi+4] or edx,edx jnz mul_overflow add ecx,eax jc mul_overflow mov eax,[esi] mul dword [edi] add edx,ecx jc mul_overflow mov [esi],eax mov [esi+4],edx or bl,bl jz mul_ok not eax not edx add eax,1 adc edx,0 mov [esi],eax mov [esi+4],edx or eax,edx jnz mul_ok not bl mul_ok: mov [esi+13],bl pop edx or dx,dx jz mul_calculated cmp word [edi+8],0 jne invalid_value cmp byte [esi+8],0 je mul_first_register_ok call get_byte_scale imul byte [esi+10] mov dl,ah cbw cmp ah,dl jne value_out_of_range mov [esi+10],al or al,al jnz mul_first_register_ok mov [esi+8],al mul_first_register_ok: cmp byte [esi+9],0 je mul_calculated call get_byte_scale imul byte [esi+11] mov dl,ah cbw cmp ah,dl jne value_out_of_range mov [esi+11],al or al,al jnz mul_calculated mov [esi+9],al mul_calculated: pop esi jmp calculation_loop mul_overflow: pop edx esi call recoverable_overflow jmp calculation_loop get_byte_scale: mov al,[edi] cbw cwde cdq cmp edx,[edi+4] jne value_out_of_range cmp eax,[edi] jne value_out_of_range ret calculate_div: push esi edx mov esi,ebx call div_64 pop edx or dx,dx jz div_calculated cmp byte [esi+8],0 je div_first_register_ok call get_byte_scale or al,al jz value_out_of_range mov al,[esi+10] cbw idiv byte [edi] or ah,ah jnz invalid_use_of_symbol mov [esi+10],al div_first_register_ok: cmp byte [esi+9],0 je div_calculated call get_byte_scale or al,al jz value_out_of_range mov al,[esi+11] cbw idiv byte [edi] or ah,ah jnz invalid_use_of_symbol mov [esi+11],al div_calculated: pop esi jmp calculation_loop calculate_mod: push esi mov esi,ebx call div_64 mov [esi],eax mov [esi+4],edx mov [esi+13],bh pop esi jmp calculation_loop calculate_and: mov eax,[edi] mov edx,[edi+4] mov cl,[edi+13] and [ebx],eax and [ebx+4],edx and [ebx+13],cl jmp calculation_loop calculate_or: mov eax,[edi] mov edx,[edi+4] mov cl,[edi+13] or [ebx],eax or [ebx+4],edx or [ebx+13],cl jmp calculation_loop calculate_xor: mov eax,[edi] mov edx,[edi+4] mov cl,[edi+13] xor [ebx],eax xor [ebx+4],edx xor [ebx+13],cl jmp calculation_loop shr_negative: mov byte [edi+13],0 not dword [edi] not dword [edi+4] add dword [edi],1 adc dword [edi+4],0 jc shl_over calculate_shl: cmp byte [edi+13],0 jne shl_negative mov edx,[ebx+4] mov eax,[ebx] cmp dword [edi+4],0 jne shl_over movsx ecx,byte [ebx+13] xchg ecx,[edi] cmp ecx,64 je shl_max ja shl_over cmp ecx,32 jae shl_high shld [edi],edx,cl shld edx,eax,cl shl eax,cl mov [ebx],eax mov [ebx+4],edx jmp shl_done shl_over: cmp byte [ebx+13],0 jne shl_overflow shl_max: movsx ecx,byte [ebx+13] cmp eax,ecx jne shl_overflow cmp edx,ecx jne shl_overflow xor eax,eax mov [ebx],eax mov [ebx+4],eax jmp calculation_loop shl_high: sub cl,32 shld [edi],edx,cl shld edx,eax,cl shl eax,cl mov [ebx+4],eax and dword [ebx],0 cmp edx,[edi] jne shl_overflow shl_done: movsx eax,byte [ebx+13] cmp eax,[edi] je calculation_loop shl_overflow: call recoverable_overflow jmp calculation_loop shl_negative: mov byte [edi+13],0 not dword [edi] not dword [edi+4] add dword [edi],1 adc dword [edi+4],0 jnc calculate_shr dec dword [edi+4] calculate_shr: cmp byte [edi+13],0 jne shr_negative mov edx,[ebx+4] mov eax,[ebx] cmp dword [edi+4],0 jne shr_over mov ecx,[edi] cmp ecx,64 jae shr_over push esi movsx esi,byte [ebx+13] cmp ecx,32 jae shr_high shrd eax,edx,cl shrd edx,esi,cl mov [ebx],eax mov [ebx+4],edx pop esi jmp calculation_loop shr_high: sub cl,32 shrd edx,esi,cl mov [ebx],edx mov [ebx+4],esi pop esi jmp calculation_loop shr_over: movsx eax,byte [ebx+13] mov dword [ebx],eax mov dword [ebx+4],eax jmp calculation_loop calculate_not: cmp word [edi+8],0 jne invalid_expression cmp byte [edi+12],0 je not_ok call recoverable_misuse not_ok: not dword [edi] not dword [edi+4] not byte [edi+13] add edi,14h jmp calculation_loop calculate_bsf: cmp word [edi+8],0 jne invalid_expression cmp byte [edi+12],0 je bsf_ok call recoverable_misuse bsf_ok: xor ecx,ecx bsf eax,[edi] jnz finish_bs mov ecx,32 bsf eax,[edi+4] jnz finish_bs cmp byte [edi+13],0 jne finish_bs bs_overflow: call recoverable_overflow add edi,14h jmp calculation_loop calculate_bsr: cmp word [edi+8],0 jne invalid_expression cmp byte [edi+12],0 je bsr_ok call recoverable_misuse bsr_ok: cmp byte [edi+13],0 jne bs_overflow mov ecx,32 bsr eax,[edi+4] jnz finish_bs xor ecx,ecx bsr eax,[edi] jz bs_overflow finish_bs: add eax,ecx xor edx,edx mov [edi],eax mov [edi+4],edx mov [edi+13],dl add edi,14h jmp calculation_loop calculate_neg: cmp byte [edi+8],0 je neg_first_register_ok neg byte [edi+10] jo invalid_expression neg_first_register_ok: cmp byte [edi+9],0 je neg_second_register_ok neg byte [edi+11] jo invalid_expression neg_second_register_ok: neg byte [edi+12] xor eax,eax xor edx,edx xor cl,cl xchg eax,[edi] xchg edx,[edi+4] xchg cl,[edi+13] sub [edi],eax sbb [edi+4],edx sbb [edi+13],cl jp neg_sign_ok call recoverable_overflow neg_sign_ok: add edi,14h jmp calculation_loop calculate_rva: cmp word [edi+8],0 jne invalid_expression mov al,[output_format] cmp al,5 je calculate_gotoff cmp al,4 je calculate_coff_rva cmp al,3 jne invalid_expression test [format_flags],8 jnz pe64_rva mov al,2 bt [resolver_flags],0 jc rva_type_ok xor al,al rva_type_ok: cmp byte [edi+12],al je rva_ok call recoverable_misuse rva_ok: mov byte [edi+12],0 mov eax,[code_start] mov eax,[eax+34h] xor edx,edx finish_rva: sub [edi],eax sbb [edi+4],edx sbb byte [edi+13],0 jp rva_finished call recoverable_overflow rva_finished: add edi,14h jmp calculation_loop pe64_rva: mov al,4 bt [resolver_flags],0 jc pe64_rva_type_ok xor al,al pe64_rva_type_ok: cmp byte [edi+12],al je pe64_rva_ok call recoverable_misuse pe64_rva_ok: mov byte [edi+12],0 mov eax,[code_start] mov edx,[eax+34h] mov eax,[eax+30h] jmp finish_rva calculate_gotoff: test [format_flags],1 jnz calculate_elf_dyn_rva test [format_flags],8 jnz invalid_expression calculate_coff_rva: mov dl,5 cmp byte [edi+12],2 je change_value_type incorrect_change_of_value_type: call recoverable_misuse change_value_type: mov byte [edi+12],dl add edi,14h jmp calculation_loop calculate_elf_dyn_rva: xor dl,dl test byte [edi+12],1 jnz incorrect_change_of_value_type jmp change_value_type calculate_plt: cmp word [edi+8],0 jne invalid_expression cmp [output_format],5 jne invalid_expression test [format_flags],1 jnz invalid_expression mov dl,6 mov dh,2 test [format_flags],8 jz check_value_for_plt mov dh,4 check_value_for_plt: mov eax,[edi] or eax,[edi+4] jnz incorrect_change_of_value_type cmp byte [edi+12],dh jne incorrect_change_of_value_type mov eax,[edi+16] cmp byte [eax],80h jne incorrect_change_of_value_type jmp change_value_type div_64: xor ebx,ebx cmp dword [edi],0 jne divider_ok cmp dword [edi+4],0 jne divider_ok cmp [next_pass_needed],0 je value_out_of_range jmp div_done divider_ok: cmp byte [esi+13],0 je div_first_sign_ok mov eax,[esi] mov edx,[esi+4] not eax not edx add eax,1 adc edx,0 mov [esi],eax mov [esi+4],edx or eax,edx jz value_out_of_range xor bx,-1 div_first_sign_ok: cmp byte [edi+13],0 je div_second_sign_ok mov eax,[edi] mov edx,[edi+4] not eax not edx add eax,1 adc edx,0 mov [edi],eax mov [edi+4],edx or eax,edx jz value_out_of_range xor bl,-1 div_second_sign_ok: cmp dword [edi+4],0 jne div_high mov ecx,[edi] mov eax,[esi+4] xor edx,edx div ecx mov [esi+4],eax mov eax,[esi] div ecx mov [esi],eax mov eax,edx xor edx,edx jmp div_done div_high: push ebx mov eax,[esi+4] xor edx,edx div dword [edi+4] mov ebx,[esi] mov [esi],eax and dword [esi+4],0 mov ecx,edx mul dword [edi] div_high_loop: cmp ecx,edx ja div_high_done jb div_high_large_correction cmp ebx,eax jae div_high_done div_high_correction: dec dword [esi] sub eax,[edi] sbb edx,[edi+4] jnc div_high_loop div_high_done: sub ebx,eax sbb ecx,edx mov edx,ecx mov eax,ebx pop ebx jmp div_done div_high_large_correction: push eax edx mov eax,edx sub eax,ecx xor edx,edx div dword [edi+4] shr eax,1 jz div_high_small_correction sub [esi],eax push eax mul dword [edi+4] sub dword [esp+4],eax pop eax mul dword [edi] sub dword [esp+4],eax sbb dword [esp],edx pop edx eax jmp div_high_loop div_high_small_correction: pop edx eax jmp div_high_correction div_done: or bh,bh jz remainder_ok not eax not edx add eax,1 adc edx,0 mov ecx,eax or ecx,edx jnz remainder_ok not bh remainder_ok: or bl,bl jz div_ok not dword [esi] not dword [esi+4] add dword [esi],1 adc dword [esi+4],0 mov ecx,[esi] or ecx,[esi+4] jnz div_ok not bl div_ok: mov [esi+13],bl ret store_label_reference: cmp [symbols_file],0 je label_reference_ok cmp [next_pass_needed],0 jne label_reference_ok mov eax,[tagged_blocks] mov dword [eax-4],2 mov dword [eax-8],4 sub eax,8+4 cmp eax,edi jbe out_of_memory mov [tagged_blocks],eax mov [eax],ebx label_reference_ok: ret convert_fp: inc esi and word [edi+8],0 and word [edi+12],0 mov al,[value_size] cmp al,2 je convert_fp_word cmp al,4 je convert_fp_dword test al,not 8 jz convert_fp_qword call recoverable_misuse convert_fp_qword: xor eax,eax xor edx,edx cmp word [esi+8],8000h je fp_qword_store mov bx,[esi+8] mov eax,[esi] mov edx,[esi+4] add eax,eax adc edx,edx mov ecx,edx shr edx,12 shrd eax,ecx,12 jnc fp_qword_ok add eax,1 adc edx,0 bt edx,20 jnc fp_qword_ok and edx,1 shl 20 - 1 inc bx shr edx,1 rcr eax,1 fp_qword_ok: add bx,3FFh cmp bx,7FFh jge value_out_of_range cmp bx,0 jg fp_qword_exp_ok or edx,1 shl 20 mov cx,bx neg cx inc cx cmp cx,52+1 ja value_out_of_range cmp cx,32 jb fp_qword_small_shift sub cx,32 mov eax,edx xor edx,edx shr eax,cl jmp fp_qword_shift_done fp_qword_small_shift: mov ebx,edx shr edx,cl shrd eax,ebx,cl fp_qword_shift_done: mov bx,0 jnc fp_qword_exp_ok add eax,1 adc edx,0 test edx,1 shl 20 jz fp_qword_exp_ok and edx,1 shl 20 - 1 inc bx fp_qword_exp_ok: shl ebx,20 or edx,ebx jnz fp_qword_store or eax,eax jz value_out_of_range fp_qword_store: mov bl,[esi+11] shl ebx,31 or edx,ebx mov [edi],eax mov [edi+4],edx add esi,13 ret convert_fp_word: xor eax,eax cmp word [esi+8],8000h je fp_word_store mov bx,[esi+8] mov ax,[esi+6] shl ax,1 shr ax,6 jnc fp_word_ok inc ax bt ax,10 jnc fp_word_ok and ax,1 shl 10 - 1 inc bx shr ax,1 fp_word_ok: add bx,0Fh cmp bx,01Fh jge value_out_of_range cmp bx,0 jg fp_word_exp_ok or ax,1 shl 10 mov cx,bx neg cx inc cx cmp cx,10+1 ja value_out_of_range xor bx,bx shr ax,cl jnc fp_word_exp_ok inc ax test ax,1 shl 10 jz fp_word_exp_ok and ax,1 shl 10 - 1 inc bx fp_word_exp_ok: shl bx,10 or ax,bx jz value_out_of_range fp_word_store: mov bl,[esi+11] shl bx,15 or ax,bx mov [edi],eax xor eax,eax mov [edi+4],eax add esi,13 ret convert_fp_dword: xor eax,eax cmp word [esi+8],8000h je fp_dword_store mov bx,[esi+8] mov eax,[esi+4] shl eax,1 shr eax,9 jnc fp_dword_ok inc eax bt eax,23 jnc fp_dword_ok and eax,1 shl 23 - 1 inc bx shr eax,1 fp_dword_ok: add bx,7Fh cmp bx,0FFh jge value_out_of_range cmp bx,0 jg fp_dword_exp_ok or eax,1 shl 23 mov cx,bx neg cx inc cx cmp cx,23+1 ja value_out_of_range xor bx,bx shr eax,cl jnc fp_dword_exp_ok inc eax test eax,1 shl 23 jz fp_dword_exp_ok and eax,1 shl 23 - 1 inc bx fp_dword_exp_ok: shl ebx,23 or eax,ebx jz value_out_of_range fp_dword_store: mov bl,[esi+11] shl ebx,31 or eax,ebx mov [edi],eax xor eax,eax mov [edi+4],eax add esi,13 ret get_string_value: inc esi lods dword [esi] mov ecx,eax cmp ecx,8 ja value_out_of_range mov edx,edi xor eax,eax stos dword [edi] stos dword [edi] mov edi,edx rep movs byte [edi],[esi] mov edi,edx inc esi and word [edi+8],0 and word [edi+12],0 ret get_byte_value: mov [value_size],1 or [operand_flags],1 call calculate_value or al,al jz check_byte_value call recoverable_misuse check_byte_value: mov eax,[edi] mov edx,[edi+4] cmp byte [edi+13],0 je byte_positive cmp edx,-1 jne range_exceeded cmp eax,-100h jb range_exceeded ret byte_positive: test edx,edx jnz range_exceeded cmp eax,100h jae range_exceeded return_byte_value: ret range_exceeded: xor eax,eax xor edx,edx recoverable_overflow: cmp [error_line],0 jne ignore_overflow push [current_line] pop [error_line] mov [error],value_out_of_range or [value_undefined],-1 ignore_overflow: ret recoverable_misuse: cmp [error_line],0 jne ignore_misuse push [current_line] pop [error_line] mov [error],invalid_use_of_symbol ignore_misuse: ret get_word_value: mov [value_size],2 or [operand_flags],1 call calculate_value cmp al,2 jb check_word_value call recoverable_misuse check_word_value: mov eax,[edi] mov edx,[edi+4] cmp byte [edi+13],0 je word_positive cmp edx,-1 jne range_exceeded cmp eax,-10000h jb range_exceeded ret word_positive: test edx,edx jnz range_exceeded cmp eax,10000h jae range_exceeded ret get_dword_value: mov [value_size],4 or [operand_flags],1 call calculate_value cmp al,4 jne check_dword_value mov [value_type],2 mov eax,[edi] cdq cmp edx,[edi+4] jne range_exceeded mov ecx,edx sar ecx,31 cmp cl,[value_sign] jne range_exceeded ret check_dword_value: mov eax,[edi] mov edx,[edi+4] cmp byte [edi+13],0 je dword_positive cmp edx,-1 jne range_exceeded ret dword_positive: test edx,edx jne range_exceeded ret get_pword_value: mov [value_size],6 or [operand_flags],1 call calculate_value cmp al,4 jne check_pword_value call recoverable_misuse check_pword_value: mov eax,[edi] mov edx,[edi+4] cmp byte [edi+13],0 je pword_positive cmp edx,-10000h jb range_exceeded ret pword_positive: cmp edx,10000h jae range_exceeded ret get_qword_value: mov [value_size],8 or [operand_flags],1 call calculate_value check_qword_value: mov eax,[edi] mov edx,[edi+4] ret get_count_value: mov [value_size],8 or [operand_flags],1 call calculate_expression cmp word [edi+8],0 jne invalid_value mov [value_sign],0 mov al,[edi+12] or al,al jz check_count_value call recoverable_misuse check_count_value: cmp byte [edi+13],0 jne invalid_count_value mov eax,[edi] mov edx,[edi+4] or edx,edx jnz invalid_count_value ret invalid_count_value: cmp [error_line],0 jne zero_count mov eax,[current_line] mov [error_line],eax mov [error],invalid_value zero_count: xor eax,eax ret get_value: mov [operand_size],0 lods byte [esi] call get_size_operator cmp al,'(' jne invalid_value mov al,[operand_size] cmp al,1 je value_byte cmp al,2 je value_word cmp al,4 je value_dword cmp al,6 je value_pword cmp al,8 je value_qword or al,al jnz invalid_value mov [value_size],al call calculate_value mov eax,[edi] mov edx,[edi+4] ret calculate_value: call calculate_expression cmp word [edi+8],0 jne invalid_value mov eax,[edi+16] mov [symbol_identifier],eax mov al,[edi+13] mov [value_sign],al mov al,[edi+12] mov [value_type],al ret value_qword: call get_qword_value truncated_value: mov [value_sign],0 ret value_pword: call get_pword_value movzx edx,dx jmp truncated_value value_dword: call get_dword_value xor edx,edx jmp truncated_value value_word: call get_word_value xor edx,edx movzx eax,ax jmp truncated_value value_byte: call get_byte_value xor edx,edx movzx eax,al jmp truncated_value get_address_word_value: mov [address_size],2 mov [value_size],2 mov [free_address_range],0 jmp calculate_address get_address_dword_value: mov [address_size],4 mov [value_size],4 mov [free_address_range],0 jmp calculate_address get_address_qword_value: mov [address_size],8 mov [value_size],8 mov [free_address_range],0 jmp calculate_address get_address_value: mov [address_size],0 mov [value_size],8 or [free_address_range],-1 calculate_address: cmp byte [esi],'.' je invalid_address call calculate_expression mov eax,[edi+16] mov [address_symbol],eax mov al,[edi+13] mov [address_sign],al mov al,[edi+12] mov [value_type],al cmp al,0 je address_size_ok jg get_address_symbol_size neg al get_address_symbol_size: cmp al,6 je special_address_type_32bit cmp al,5 je special_address_type_32bit ja invalid_address_type test al,1 jnz invalid_address_type shl al,5 jmp address_symbol_ok invalid_address_type: call recoverable_misuse special_address_type_32bit: mov al,40h address_symbol_ok: mov ah,[address_size] or [address_size],al shr al,4 or ah,ah jz address_size_ok cmp al,ah je address_size_ok cmp ax,0408h je address_sizes_mixed cmp ax,0804h jne address_sizes_do_not_agree address_sizes_mixed: cmp [value_type],4 jne address_sizes_mixed_type_ok mov [value_type],2 address_sizes_mixed_type_ok: mov eax,[edi] cdq cmp edx,[edi+4] je address_size_ok cmp [error_line],0 jne address_size_ok call recoverable_overflow address_size_ok: xor ebx,ebx xor ecx,ecx mov cl,[value_type] shl ecx,16 mov ch,[address_size] cmp word [edi+8],0 je check_immediate_address mov al,[edi+8] mov dl,[edi+10] call get_address_register mov al,[edi+9] mov dl,[edi+11] call get_address_register mov ax,bx shr ah,4 shr al,4 or bh,bh jz check_address_registers or bl,bl jz check_address_registers cmp al,ah jne check_vsib check_address_registers: or al,ah cmp al,0Ch jae check_vsib cmp al,6 je check_vsib cmp al,7 je check_vsib mov ah,[address_size] and ah,0Fh jz address_registers_sizes_ok cmp al,ah jne invalid_address address_registers_sizes_ok: cmp al,4 je sib_allowed cmp al,8 je sib_allowed cmp al,9 je check_ip_relative_address cmp cl,1 ja invalid_address cmp [free_address_range],0 jne check_qword_value jmp check_word_value address_sizes_do_not_match: cmp al,0Fh jne invalid_address mov al,bh and al,0Fh cmp al,ah jne invalid_address check_ip_relative_address: or bl,bl jnz invalid_address cmp bh,98h je check_rip_relative_address cmp bh,94h jne invalid_address cmp [free_address_range],0 je check_dword_value mov eax,[edi] mov edx,[edi+4] ret check_rip_relative_address: mov eax,[edi] cdq cmp edx,[edi+4] jne range_exceeded cmp dl,[edi+13] jne range_exceeded ret get_address_register: or al,al jz address_register_ok cmp dl,1 jne scaled_register or bh,bh jnz scaled_register mov bh,al address_register_ok: ret scaled_register: or bl,bl jnz invalid_address mov bl,al mov cl,dl jmp address_register_ok sib_allowed: or bh,bh jnz check_index_with_base cmp cl,3 je special_index_scale cmp cl,5 je special_index_scale cmp cl,9 je special_index_scale cmp cl,2 jne check_index_scale cmp bl,45h jne special_index_scale cmp [code_type],64 je special_index_scale cmp [segment_register],4 jne special_index_scale cmp [value_type],0 jne check_index_scale mov al,[edi] cbw cwde cmp eax,[edi] jne check_index_scale cdq cmp edx,[edi+4] jne check_immediate_address special_index_scale: mov bh,bl dec cl check_immediate_address: cmp [free_address_range],0 jne check_qword_value mov al,[address_size] and al,0Fh cmp al,2 je check_word_value cmp al,4 je check_dword_value cmp al,8 je check_qword_value or al,al jnz invalid_value cmp [code_type],64 jne check_dword_value jmp check_qword_value check_index_with_base: cmp cl,1 jne check_index_scale cmp bl,44h je swap_base_with_index cmp bl,84h je swap_base_with_index cmp [code_type],64 je check_for_rbp_base cmp bl,45h jne check_for_ebp_base cmp [segment_register],3 je swap_base_with_index jmp check_immediate_address check_for_ebp_base: cmp bh,45h jne check_immediate_address cmp [segment_register],4 jne check_immediate_address swap_base_with_index: xchg bl,bh jmp check_immediate_address check_for_rbp_base: cmp bh,45h je swap_base_with_index cmp bh,85h je swap_base_with_index jmp check_immediate_address check_index_scale: test cl,not 1111b jnz invalid_address mov al,cl dec al and al,cl jz check_immediate_address jmp invalid_address check_vsib: xor ah,ah check_vsib_base: test bh,bh jz check_vsib_index mov al,bh shr al,4 cmp al,4 je check_vsib_base_size cmp [code_type],64 jne swap_vsib_registers cmp al,8 jne swap_vsib_registers check_vsib_base_size: mov ah,[address_size] and ah,0Fh jz check_vsib_index cmp al,ah jne invalid_address check_vsib_index: mov al,bl and al,0E0h cmp al,0C0h jae check_index_scale cmp al,60h je check_index_scale jmp invalid_address swap_vsib_registers: xor ah,-1 jz invalid_address cmp cl,1 ja invalid_address xchg bl,bh mov cl,1 jmp check_vsib_base calculate_relative_offset: cmp [value_undefined],0 jne relative_offset_ok test bh,bh setne ch cmp bx,[ds:ebp+10h] je origin_registers_ok xchg bh,bl xchg ch,cl cmp bx,[ds:ebp+10h] jne invalid_value origin_registers_ok: cmp cx,[ds:ebp+10h+2] jne invalid_value mov bl,[address_sign] add eax,[ds:ebp] adc edx,[ds:ebp+4] adc bl,[ds:ebp+8] sub eax,edi sbb edx,0 sbb bl,0 mov [value_sign],bl mov bl,[value_type] mov ecx,[address_symbol] mov [symbol_identifier],ecx test bl,1 jnz relative_offset_unallowed cmp bl,6 je plt_relative_offset mov bh,[ds:ebp+9] cmp bl,bh je set_relative_offset_type cmp bx,0402h je set_relative_offset_type relative_offset_unallowed: call recoverable_misuse set_relative_offset_type: cmp [value_type],0 je relative_offset_ok mov [value_type],0 cmp ecx,[ds:ebp+14h] je relative_offset_ok mov [value_type],3 relative_offset_ok: ret plt_relative_offset: mov [value_type],7 cmp byte [ds:ebp+9],2 je relative_offset_ok cmp byte [ds:ebp+9],4 jne recoverable_misuse ret calculate_logical_expression: xor al,al calculate_embedded_logical_expression: mov [logical_value_wrapping],al call get_logical_value logical_loop: cmp byte [esi],'|' je logical_or cmp byte [esi],'&' je logical_and ret logical_or: inc esi or al,al jnz logical_value_already_determined push eax call get_logical_value pop ebx or al,bl jmp logical_loop logical_and: inc esi or al,al jz logical_value_already_determined push eax call get_logical_value pop ebx and al,bl jmp logical_loop logical_value_already_determined: push eax call skip_logical_value jc invalid_expression pop eax jmp logical_loop get_value_for_comparison: mov [value_size],8 or [operand_flags],1 lods byte [esi] call calculate_expression cmp byte [edi+8],0 jne first_register_size_ok mov byte [edi+10],0 first_register_size_ok: cmp byte [edi+9],0 jne second_register_size_ok mov byte [edi+11],0 second_register_size_ok: mov eax,[edi+16] mov [symbol_identifier],eax mov al,[edi+13] mov [value_sign],al mov bl,[edi+12] mov eax,[edi] mov edx,[edi+4] mov ecx,[edi+8] ret get_logical_value: xor al,al check_for_negation: cmp byte [esi],'~' jne negation_ok inc esi xor al,-1 jmp check_for_negation negation_ok: push eax mov al,[esi] cmp al,91h je logical_expression cmp al,0FFh je invalid_expression cmp al,88h je check_for_defined cmp al,8Ah je check_for_earlier_defined cmp al,89h je check_for_used cmp al,'0' je given_false cmp al,'1' je given_true cmp al,'(' jne invalid_value call get_value_for_comparison mov bh,[value_sign] push eax edx push [symbol_identifier] push ebx ecx mov al,[esi] or al,al jz logical_number cmp al,0Fh je logical_number cmp al,92h je logical_number cmp al,'&' je logical_number cmp al,'|' je logical_number inc esi mov [compare_type],al cmp byte [esi],'(' jne invalid_value call get_value_for_comparison cmp bl,[esp+4] jne values_not_relative or bl,bl jz check_values_registers mov ebx,[symbol_identifier] cmp ebx,[esp+8] jne values_not_relative check_values_registers: cmp ecx,[esp] je values_relative ror ecx,16 xchg ch,cl ror ecx,16 xchg ch,cl cmp ecx,[esp] je values_relative values_not_relative: cmp [compare_type],0F8h jne invalid_comparison add esp,12+8 jmp return_false invalid_comparison: call recoverable_misuse values_relative: pop ebx shl ebx,16 mov bx,[esp] add esp,8 pop ecx ebp cmp [compare_type],'=' je check_equal cmp [compare_type],0F1h je check_not_equal cmp [compare_type],0F8h je return_true test ebx,0FFFF0000h jz check_less_or_greater call recoverable_misuse check_less_or_greater: cmp [compare_type],'>' je check_greater cmp [compare_type],'<' je check_less cmp [compare_type],0F2h je check_not_less cmp [compare_type],0F3h je check_not_greater jmp invalid_expression check_equal: cmp bh,[value_sign] jne return_false cmp eax,ebp jne return_false cmp edx,ecx jne return_false jmp return_true check_greater: cmp bh,[value_sign] jg return_true jl return_false cmp edx,ecx jb return_true ja return_false cmp eax,ebp jb return_true jae return_false check_less: cmp bh,[value_sign] jg return_false jl return_true cmp edx,ecx jb return_false ja return_true cmp eax,ebp jbe return_false ja return_true check_not_less: cmp bh,[value_sign] jg return_true jl return_false cmp edx,ecx jb return_true ja return_false cmp eax,ebp jbe return_true ja return_false check_not_greater: cmp bh,[value_sign] jg return_false jl return_true cmp edx,ecx jb return_false ja return_true cmp eax,ebp jb return_false jae return_true check_not_equal: cmp bh,[value_sign] jne return_true cmp eax,ebp jne return_true cmp edx,ecx jne return_true jmp return_false logical_number: pop ecx ebx eax edx eax or bl,bl jnz invalid_logical_number or cx,cx jz logical_number_ok invalid_logical_number: call recoverable_misuse logical_number_ok: test bh,bh jnz return_true or eax,edx jnz return_true jmp return_false check_for_earlier_defined: or bh,-1 jmp check_if_expression_defined check_for_defined: xor bh,bh check_if_expression_defined: or bl,-1 lods word [esi] cmp ah,'(' jne invalid_expression check_expression: lods byte [esi] or al,al jz defined_string cmp al,'.' je defined_fp_value cmp al,')' je expression_checked cmp al,'!' je invalid_expression cmp al,0Fh je check_expression cmp al,10h je defined_register cmp al,11h je check_if_symbol_defined cmp al,80h jae check_expression movzx eax,al add esi,eax jmp check_expression defined_register: inc esi jmp check_expression defined_fp_value: add esi,12+1 jmp expression_checked defined_string: lods dword [esi] add esi,eax inc esi jmp expression_checked check_if_symbol_defined: lods dword [esi] cmp eax,-1 je invalid_expression cmp eax,0Fh jb check_expression je reserved_word_used_as_symbol test bh,bh jnz no_prediction test byte [eax+8],4 jnz no_prediction test byte [eax+8],1 jz symbol_predicted_undefined mov cx,[current_pass] sub cx,[eax+16] jz check_expression cmp cx,1 ja symbol_predicted_undefined or byte [eax+8],40h+80h jmp check_expression no_prediction: test byte [eax+8],1 jz symbol_undefined mov cx,[current_pass] sub cx,[eax+16] jz check_expression jmp symbol_undefined symbol_predicted_undefined: or byte [eax+8],40h and byte [eax+8],not 80h symbol_undefined: xor bl,bl jmp check_expression expression_checked: mov al,bl jmp logical_value_ok check_for_used: lods word [esi] cmp ah,2 jne invalid_expression lods dword [esi] cmp eax,0Fh jb invalid_use_of_symbol je reserved_word_used_as_symbol inc esi test byte [eax+8],8 jz not_used mov cx,[current_pass] sub cx,[eax+18] jz return_true cmp cx,1 ja not_used or byte [eax+8],10h+20h jmp return_true not_used: or byte [eax+8],10h and byte [eax+8],not 20h jmp return_false given_false: inc esi return_false: xor al,al jmp logical_value_ok given_true: inc esi return_true: or al,-1 jmp logical_value_ok logical_expression: lods byte [esi] mov dl,[logical_value_wrapping] push edx call calculate_embedded_logical_expression pop edx mov [logical_value_wrapping],dl push eax lods byte [esi] cmp al,92h jne invalid_expression pop eax logical_value_ok: pop ebx xor al,bl ret skip_symbol: lods byte [esi] or al,al jz nothing_to_skip cmp al,0Fh je nothing_to_skip cmp al,1 je skip_instruction cmp al,2 je skip_label cmp al,3 je skip_label cmp al,4 je skip_special_label cmp al,20h jb skip_assembler_symbol cmp al,'(' je skip_expression cmp al,'[' je skip_address skip_done: clc ret skip_label: add esi,2 skip_instruction: add esi,2 skip_assembler_symbol: inc esi jmp skip_done skip_special_label: add esi,4 jmp skip_done skip_address: mov al,[esi] and al,11110000b cmp al,60h jb skip_expression cmp al,70h ja skip_expression inc esi jmp skip_address skip_expression: lods byte [esi] or al,al jz skip_string cmp al,'.' je skip_fp_value cmp al,')' je skip_done cmp al,']' je skip_done cmp al,'!' je skip_expression cmp al,0Fh je skip_expression cmp al,10h je skip_register cmp al,11h je skip_label_value cmp al,80h jae skip_expression movzx eax,al add esi,eax jmp skip_expression skip_label_value: add esi,3 skip_register: inc esi jmp skip_expression skip_fp_value: add esi,12 jmp skip_done skip_string: lods dword [esi] add esi,eax inc esi jmp skip_done nothing_to_skip: dec esi stc ret expand_path: lods byte [esi] cmp al,'%' je environment_variable stos byte [edi] or al,al jnz expand_path cmp edi,[memory_end] ja out_of_memory ret environment_variable: mov ebx,esi find_variable_end: lods byte [esi] or al,al jz not_environment_variable cmp al,'%' jne find_variable_end mov byte [esi-1],0 push esi mov esi,ebx call get_environment_variable pop esi mov byte [esi-1],'%' jmp expand_path not_environment_variable: mov al,'%' stos byte [edi] mov esi,ebx jmp expand_path get_include_directory: lods byte [esi] cmp al,';' je include_directory_ok stos byte [edi] or al,al jnz get_include_directory dec esi dec edi include_directory_ok: cmp byte [edi-1],'/' je path_separator_ok cmp byte [edi-1],'\' je path_separator_ok mov al,'/' stos byte [edi] path_separator_ok: ret