# Assembly Language Programming

## August 31, 2012

### FASM – Binary To Decimal Conversion

This program takes a string containing a large binary, octal or hexadecimal unsigned integer and converts it to a decimal number. The input number can be up to 400 bytes in length (3200 binary digits, 800 hex digits, or 1066 octal digits).

A decimal representation of a binary value stored in memory is generated by decomposing it into a sum of its powers of ten:

Num = d(n) * 10n + d(n-1) * 10n-1 + … + d(0) * 100

i.e. for each power of ten from 0 to n (where 10n is the largest power of ten not greater than the binary number), the digit d needs to be found.

The algorithm to find the most significant decimal digit from a binary number is as follows:

 ```GET_DIGIT: Find the left-most decimal digit in Num: Let n be the power of ten and x=10n. (1) Start with n=0 and x=1. (2) Find the largest power of ten not greater than Num: - set n = n + 1. - multiply x by 10: x = (x << 1) + (x << 3). - repeat until: 10 * x < Num <= x. (3) Find the digit d(n): - set d=0. - subtract x from Num, until: Num < x. - increment d for each subtraction. - d is the value of the left-most decimal digit. ```

The above GET_DIGIT algorithm is applied repeatedly until all of the decimal digits have been found. Each time GET_DIGIT is called, Num is reduced until it eventually reaches zero.

The function that calls GET_DIGIT must also make sure that zeroes are correctly inserted into the string containing the decimal representation of the binary value:

 ```BINARY_TO_DECIMAL: d,n = GET_DIGIT; outstr += d; n_prev = n; while(Num > 0) { d,n = GET_DIGIT; // if (n_prev - n) is greater than 1, zeroes need to inserted before d is appended nZeroes = n_prev - n - 1; if(nZeroes > 0) { for(i = 0;i < nZeroes;i++) outstr += "0"; } outstr += d; n_prev = n; } // Num is now zero if(n > 0) { for(i = 0;i < n;i++) outstr += "0"; } ```

## The FASM x86 Code

To grab this code, select it with the mouse and copy it. It can then be pasted directly into the FASM IDE.

 ```; ------------------------------------------------------------------------------------- format PE GUI 4.0 entry start include 'win32a.inc' ; ------------------------------------------------------------------------------------- IDD_THE_DIALOG = 102 IDC_INPUT = 1000 IDC_HEX = 1001 IDC_OUTPUT = 1002 IDC_BTN_BIN_TO_DEC = 1003 IDC_BTN_HEX_TO_DEC = 1004 IDC_BTN_OCT_TO_DEC = 1005 IDC_BTN_DEC_TO_DEC = 1006 IDC_BTN_CLEAR = 1007 ; ------------------------------------------------------------------------------------- section '.code' code readable executable start: invoke GetModuleHandle,0 invoke DialogBoxParam,eax,IDD_THE_DIALOG,0,DialogProc,0 exit: invoke ExitProcess,0 ; ------------------------------------------------------------------------------------- proc DialogProc uses esi edi ebx,hwnddlg,msg,wparam,lparam cmp [msg],WM_INITDIALOG je .wminitdialog cmp [msg],WM_COMMAND je .wmcommand cmp [msg],WM_CLOSE je .wmclose xor eax,eax jmp .quit .wminitdialog: invoke SetDlgItemText,[hwnddlg],IDC_INPUT,szInputInfoText invoke SetDlgItemText,[hwnddlg],IDC_HEX,szOutputInfoText invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,szOutputInfoText jmp .done .wmcommand: cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_BIN_TO_DEC je .BIN_TO_DEC cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_HEX_TO_DEC je .HEX_TO_DEC cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_OCT_TO_DEC je .OCT_TO_DEC cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_DEC_TO_DEC je .DEC_TO_DEC cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_CLEAR je .CLEAR_DATA jmp .done .BIN_TO_DEC: invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,3200 stdcall onNullInput stdcall BinStrToBuffer stdcall PrintInputAsHex invoke SetDlgItemText,[hwnddlg],IDC_HEX,bfDisplay stdcall ConvertToDecimal invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .HEX_TO_DEC: invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,3200 stdcall onNullInput stdcall HexStrToBuffer stdcall PrintInputAsHex invoke SetDlgItemText,[hwnddlg],IDC_HEX,bfDisplay stdcall ConvertToDecimal invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .OCT_TO_DEC: invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,3200 stdcall onNullInput stdcall OctStrToBuffer stdcall PrintInputAsHex invoke SetDlgItemText,[hwnddlg],IDC_HEX,bfDisplay stdcall ConvertToDecimal invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .DEC_TO_DEC: invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,3200 stdcall onNullInput stdcall DecStrToBuffer stdcall PrintInputAsHex invoke SetDlgItemText,[hwnddlg],IDC_HEX,bfDisplay stdcall ConvertToDecimal invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .CLEAR_DATA: invoke SetDlgItemText,[hwnddlg],IDC_INPUT,szInputInfoText invoke SetDlgItemText,[hwnddlg],IDC_HEX,szOutputInfoText invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,szOutputInfoText jmp .done .wmclose: invoke EndDialog,[hwnddlg],0 .done: mov eax,1 .quit: ret endp ; ------------------------------------------------------------------------------------- proc StrToHexStr uses esi edi ; filter out any non hex digit characters from the bfDisplay string lea esi,[bfDisplay] lea edi,[bfDisplay] mov [nInputChars],word 0 .FILTER: mov al,[esi] cmp al,0 je .DONE cmp al,48 jl .NOT_HEX cmp al,57 jle .COPY cmp al,65 jl .NOT_HEX cmp al,70 jle .COPY cmp al,97 jl .NOT_HEX cmp al,102 jg .NOT_HEX .COPY: mov [edi],al inc edi inc word [nInputChars] ; max input size = 400 bytes (800 hex digits) cmp [nInputChars],800 jge .DONE .NOT_HEX: inc esi jmp .FILTER .DONE: ; null terminate the new string mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc StrToOctStr uses esi edi ; filter out any non octal digit characters from the bfDisplay string lea esi,[bfDisplay] lea edi,[bfDisplay] mov [nInputChars],word 0 .FILTER: mov al,[esi] cmp al,0 je .DONE cmp al,48 jl .NOT_OCT cmp al,55 jg .NOT_OCT .COPY: mov [edi],al inc edi inc word [nInputChars] ; max input size = 400 bytes (1066 oct digits) cmp [nInputChars],1066 jge .DONE .NOT_OCT: inc esi jmp .FILTER .DONE: ; null terminate the new string mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc StrToBinStr uses esi edi ; filter out any non binary digit characters from the bfDisplay string lea esi,[bfDisplay] lea edi,[bfDisplay] mov [nInputChars],word 0 .FILTER: mov al,[esi] cmp al,0 je .DONE cmp al,48 jl .NOT_BIN cmp al,49 jg .NOT_BIN .COPY: mov [edi],al inc edi inc word [nInputChars] ; max input size = 400 bytes (3200 binary digits) cmp [nInputChars],3200 jge .DONE .NOT_BIN: inc esi jmp .FILTER .DONE: ; null terminate the new string mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc StrToDecStr uses esi edi ; filter out any non decimal digit characters from the bfDisplay string lea esi,[bfDisplay] lea edi,[bfDisplay] mov [nInputChars],word 0 .FILTER: mov al,[esi] cmp al,0 je .DONE cmp al,48 jl .NOT_DEC cmp al,57 jg .NOT_DEC .COPY: mov [edi],al inc edi inc word [nInputChars] ; max input size = 400 bytes (963 decimal digits) cmp [nInputChars],963 jge .DONE .NOT_DEC: inc esi jmp .FILTER .DONE: ; null terminate the new string mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc HexStrToBuffer ; convert a string containing a HEX number to a value in memory ; the input string is in bfDisplay ; the value is written to InputBuffer locals count dw 0 endl ; reset the input buffer stdcall ResetInputBuffer ; filter bfDisplay so that it only contains HEX digits stdcall StrToHexStr lea esi,[bfDisplay] lea edi,[InputBuffer] ; the hex digits are read from the beginning of the display string ; and mapped to the corresponding position in the input buffer xor edx,edx mov dx,[nInputChars] ; set cx to nInputChars, loop below ends when cx = 0 mov ecx,edx ; adjust EDI: EDI = EDI + (nInputChars-1)/2 dec edx shr edx,1 add edi,edx ; use count to count the chars as they are read from the display string test [nInputChars],1 jz .GET_CHARS ; if there are an odd number of hex digits, init count to 1 inc word [count] .GET_CHARS: mov al,byte [esi] ; check for NULL terminator cmp al,0 je .DONE stdcall HexDigitToValue ; AL contains a nibble, determine where to place it in the dest byte ; if count is even, the nibble is mapped to the lower 4 bits in dest ; if count is odd, the nibble is mapped to the upper 4 bits in dest inc word [count] ; even if count AND 1 == 0 test [count],1 jz .EVEN .ODD: shl al,4 mov [edi],al jmp .NEXT .EVEN: or [edi],al dec edi .NEXT: dec cx inc esi jcxz .DONE jmp .GET_CHARS .DONE: ret endp ; ------------------------------------------------------------------------------------- proc OctStrToBuffer ; convert a string containing a OCT number to a value in memory ; the input string is in bfDisplay ; the value is written to InputBuffer ; reset the input buffer stdcall ResetInputBuffer ; filter bfDisplay so that it only contains OCT digits stdcall StrToOctStr lea esi,[bfDisplay] lea edi,[InputBuffer] xor edx,edx mov dx,[nInputChars] ; start from the end of the bfDisplay string add esi,edx dec esi ; read 8 digits at a time shr dx,3 mov cx,dx ; if there are less than 8 digits in bfDisplay, jump to .LAST jcxz .LAST .GET_DIGITS: ; process 8 digits at a time mov dx,8 ; convert to 3 bytes stdcall OctToBytes ; insert the 3 bytes into InputBuffer mov [edi],al inc edi mov [edi],ah inc edi shr eax,16 mov [edi],al inc edi dec cx jcxz .LAST jmp .GET_DIGITS .LAST: ; process the last few digits mov dx,[nInputChars] test dx,7 ; if zero, the number of digits in bfDisplay was a multiple of 8 jz .DONE and dx,7 stdcall OctToBytes mov [edi],al inc edi mov [edi],ah inc edi shr eax,16 mov [edi],al inc edi .DONE: ret endp ; ------------------------------------------------------------------------------------- proc BinStrToBuffer ; convert a string containing a BIN number to a value in memory ; the input string is in bfDisplay ; the value is written to InputBuffer ; reset the input buffer stdcall ResetInputBuffer ; filter bfDisplay so that it only contains BIN digits stdcall StrToBinStr lea esi,[bfDisplay] lea edi,[InputBuffer] ; the binary digits are read from the beginning of the display string ; and mapped to the corresponding position in the input buffer ; 8 digits are read at a time xor edx,edx mov dx,[nInputChars] ; set cx to nInputChars, loop below ends when cx = 0 mov cx,dx ; adjust EDI: EDI = EDI + (nInputChars-1)/8 dec edx shr edx,3 add edi,edx ; the input string is processed 8 digits at a time ; if the length of bfDisplay is not a multiple of 8, then the ; first byte in this string will have less than 8 binary digits ; in this case initialise dx to (nInputChars mod 8) xor edx,edx mov dx,[nInputChars] and dx,7 test dx,7 jnz .GET_BYTES mov dx,8 .GET_BYTES: ; convert 8 binary bits (digits) to a byte stdcall BinDigitsToByte ; insert byte into InputBuffer mov [edi],al sub cx,dx dec edi mov dx,8 jcxz .DONE jmp .GET_BYTES .DONE: ret endp ; ------------------------------------------------------------------------------------- proc DecStrToBuffer ; convert a string containing a DEC number to a value in memory ; the input string is in bfDisplay ; the value is written to InputBuffer ; reset the input buffer stdcall ResetInputBuffer ; clear the Ten_N buffer stdcall Init_Ten_N mov [Ten_N_Buffer],byte 0 ; filter bfDisplay so that it only contains DEC digits stdcall StrToDecStr lea esi,[bfDisplay] mov cx,[nInputChars] .GET_DIGITS: xor eax,eax ; get the digit mov al,[esi] sub al,48 cmp al,0 je .MULTIPLY ; add the digit to the lower dword of the buffer lea edx,[Ten_N_Buffer] stdcall AddDWordToBuffer .MULTIPLY: ; multiply the buffer by 10 inc esi dec cx jcxz .DONE stdcall MultiplyByTen lea eax,[TempBuffer_1] lea edx,[Ten_N_Buffer] stdcall CopyBuffer jmp .GET_DIGITS .DONE: lea eax,[Ten_N_Buffer] lea edx,[InputBuffer] stdcall CopyBuffer ret endp ; ------------------------------------------------------------------------------------- proc PrintInputAsHex uses esi edi ; print the contents of InputBuffer as a HEX value to the bfDisplay string locals count db 0 endl lea edi,[bfDisplay] lea esi,[InputBuffer] add esi,399 mov cx,400 .PRINT: ; byte to digits mov al,[esi] stdcall ByteToDigits ; add the 2 digits to the string mov [edi],ah inc edi mov [edi],al inc edi dec cx jcxz .DONE ; update ESI dec esi ; add spaces and CRLF to the output string ; a space after every 8 chars ; a CRLF after every 80 chars add [count],2 test [count],7 jne .PRINT cmp [count],79 je .ADD_CRLF mov [edi],byte 32 inc edi jmp .PRINT .ADD_CRLF: mov [count],0 mov [edi],byte 13 inc edi mov [edi],byte 10 inc edi jmp .PRINT .DONE: ; zero terminate the string mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc onNullInput ; if the bfDisplay string is empty, set it to "0" lea edi,[bfDisplay] cmp [edi],byte 0 jne .DONE mov [edi],byte 48 mov [edi+1],byte 0 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc HexDigitToValue ; convert a hex digit to a 4 bit value ; input in AL - output in AL ; is AL in the range: 48 - 57 (0 - 9) ? cmp al,48 jl .NOT_HEX cmp al,57 jg .A_Z sub al,48 jmp .DONE .A_Z: ; is AL in the range: 65 - 70 (A - B) ? cmp al,65 jl .NOT_HEX cmp al,70 jg .a_z sub al,55 jmp .DONE .a_z: ; is AL in the range: 97 - 102 (a - b) ? cmp al,97 jl .NOT_HEX cmp al,102 jg .NOT_HEX sub al,87 jmp .DONE .NOT_HEX: ; set EAX to 0xffff if input is not a valid hex digit mov eax,0xffff .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ByteToDigits ; convert 1 byte to 2 hex digits ; input in AL - output in AX ; copy AL to AH mov ah,al ; AH: get the upper 4 bits of the byte shr ah,4 ; nibble to hex digit add ah,48 cmp ah,57 jle .NEXT add ah,7 .NEXT: ; AL: get the lower 4 bits of the byte and al,0xf ; nibble to hex digit add al,48 cmp al,57 jle .DONE add al,7 .DONE: ; output is in AX ret endp ; ------------------------------------------------------------------------------------- proc BinDigitsToByte uses ecx edx ; convert up to 8 binary digits to a byte value ; number of digits is in EDX ; ESI is initialised outside of this proc mov cx,dx xor eax,eax .GET_DIGITS: mov dl,[esi] inc esi cmp dl,48 je .SHIFT or al,1 .SHIFT: dec cx jcxz .DONE shl al,1 jmp .GET_DIGITS .DONE: ; AL now contains the byte value ret endp ; ------------------------------------------------------------------------------------- proc OctToBytes uses ecx ; convert up to 8 octal digits to 3 bytes ; bytes are returned in EAX ; ESI points to the least significant digit ; ESI is set outside this proc ; the number of digits to process is passed in DX locals nDigits dw 0 endl mov [nDigits],dx xor eax,eax ; CX is an index (0-7) xor ecx,ecx mov cl,dl ; if there are zero digits, do nothing jcxz .DONE ; make sure CX = 0-7 dec cx .GET_DIGITS: mov dl,[esi] sub dl,48 ; OR the value into the upper 3 bits of EAX shl edx,29 or eax,edx dec esi jcxz .DONE ; right shift EAX by 3 bits shr eax,3 dec cx jmp .GET_DIGITS .DONE: ; adjust EAX so that the final value is in the lower 3 bytes shr eax,8 cmp [nDigits],8 jge .QUIT ; if there were less than 8 digits, further adjust EAX ; i.e. for each digit less than 8, shift right EAX by 3 bits mov cx,8 sub cx,[nDigits] ; multiply CX by 3 mov dx,cx shl dx,1 add cx,dx ; adjust EAX shr eax,cl .QUIT: ret endp ; ------------------------------------------------------------------------------------- proc ResetInputBuffer uses edi ecx ; clear the input buffer lea edi,[InputBuffer] mov cx,0 .CLEAR: mov [edi],byte 0 inc edi inc cx cmp cx,400 jl .CLEAR ret endp ; ------------------------------------------------------------------------------------- proc ConvertToDecimal ; convert the hex value stored in InputBuffer to a string of decimal digits locals Last_Power_N dw 0 endl lea edi,[bfDisplay] .ZERO_INPUT: ; if the input is zero, just exit lea eax,[InputBuffer] stdcall IsZero cmp al,1 je .DONE .FIRST: ; get the first digit stdcall GetNextDigit jmp .ADD_DIGIT .PROCESS: ; get the next digit stdcall GetNextDigit ; update the power of ten: N mov cx,[Last_Power_N] sub cx,[Power_N] cmp cx,1 jle .ADD_DIGIT sub cx,1 .INSERT: ; if the difference between the current N and the previous N ; is greater than 1, insert zeroes into the output string mov [edi],byte 48 inc edi dec cx jcxz .ADD_DIGIT jmp .INSERT .ADD_DIGIT: ; add the digit to the string mov al,[Digit] mov [edi],al inc edi mov ax,[Power_N] mov [Last_Power_N],ax ; has InputBuffer been reduced to zero lea eax,[InputBuffer] stdcall IsZero cmp al,1 je .FINAL jmp .PROCESS .FINAL: mov cx,[Power_N] jcxz .DONE .APPEND: ; if InputBuffer has been reduced to zero, but N is still ; greater than zero, append zeroes to the output string mov [edi],byte 48 inc edi dec cx jcxz .DONE jmp .APPEND .DONE: ; NULL terminate bfDisplay mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc GetNextDigit ; find the most siginificant decimal digit for the hex value stored in InputBuffer ; set Ten(N) = 1 stdcall Init_Ten_N mov [Power_N],word 0 .FIND: ; Ten(N) = Ten(N) * 10 stdcall MultiplyByTen lea eax,[TempBuffer_1] lea edx,[InputBuffer] ; when(TempBuffer_1 greater than InputBuffer) goto .GET_DIGIT stdcall Compare cmp al,4 je .GET_DIGIT ; update Ten(N) lea eax,[TempBuffer_1] lea edx,[Ten_N_Buffer] stdcall CopyBuffer inc [Power_N] jmp .FIND .GET_DIGIT: mov [Digit],byte 0 .CALC: ; InputBuffer = InputBuffer - Ten(N) lea eax,[Ten_N_Buffer] lea edx,[InputBuffer] stdcall CalcDiff inc [Digit] lea eax,[InputBuffer] lea edx,[Ten_N_Buffer] ; when((InputBuffer less than Ten(N)) = TRUE) break stdcall Compare cmp al,1 je .DONE jmp .CALC .DONE: ; convert Digit to an ASCII value add [Digit],byte 48 ret endp ; ------------------------------------------------------------------------------------- proc Init_Ten_N uses edi ecx ; clear the Ten_N_Buffer value and then init to 1 lea edi,[Ten_N_Buffer] mov cx,0 .CLEAR: mov [edi],byte 0 inc edi inc cx cmp cx,400 jl .CLEAR ; set equal to 1 mov [Ten_N_Buffer],byte 1 ret endp ; ------------------------------------------------------------------------------------- proc MultiplyByTen ; multiply the value in Ten_N_Buffer by 10 ; result is saved in TempBuffer_1 ; A x 10 = SHL(A,1) + SHL(A,3) ; TempBuffer_1 = A lea eax,[Ten_N_Buffer] lea edx,[TempBuffer_1] stdcall CopyBuffer ; SHL(TempBuffer_1,1) lea eax,[TempBuffer_1] stdcall ShiftLeft ; TempBuffer_2 = SHL(A,1) lea eax,[TempBuffer_1] lea edx,[TempBuffer_2] stdcall CopyBuffer ; TempBuffer_2 = SHL(A,2) lea eax,[TempBuffer_2] stdcall ShiftLeft ; TempBuffer_2 = SHL(A,3) lea eax,[TempBuffer_2] stdcall ShiftLeft ; TempBuffer_1 = TempBuffer_1 + TempBuffer_2 lea eax,[TempBuffer_2] lea edx,[TempBuffer_1] stdcall CalcSum ret endp ; ------------------------------------------------------------------------------------- proc AddDWordToBuffer uses edi ecx ; Add a dword to a 400 byte value ; dword is in EAX ; address of dest number is in EDX mov edi,edx mov cx,0 ; add the dword to the dest add dword [edi],eax ; exit if no carry jnc .DONE .ADD_C: ; add in the carry bit add edi,4 add dword [edi],1 ; exit if no carry jnc .DONE add cx,4 cmp cx,400 jl .ADD_C .DONE: ret endp ; ------------------------------------------------------------------------------------- proc CalcSum uses esi edi ecx ; Add two 400 byte values ; address of src number is in EAX ; address of dest number is in EDX mov esi,eax mov edi,edx mov cx,0 ; save CF from iteration to iteration ; init CF = 0 clc ; push flags register to the stack pushf .SUM: mov eax,dword [esi] ; get the flags register from the stack popf ; [EDI] = [EDI] + [ESI] + CF adc dword [edi],eax ; save the flags register to the stack, for the next iteration pushf ; these affect the CF, which is why it has to be saved to the stack add esi,4 add edi,4 add cx,4 ; cmp also affects the CF cmp cx,400 jl .SUM ; clean up the stack popf ret endp ; ------------------------------------------------------------------------------------- proc CalcDiff uses esi edi ecx ; Calc the difference between two 400 byte numbers ; dest = dest - src ; address of src number is in eax ; address of dest number is in edx mov esi,eax mov edi,edx mov cx,0 ; compute diff as: dest = dest + ~src + 1 ; the 1 is introduced by initialising CF to 1 ; save CF from iteration to iteration ; init CF = 1 stc ; push flags register to the stack pushf .SUB: mov eax,dword [esi] ; ~src here: not eax ; get the flags register from the stack popf ; [EDI] = [EDI] + ~[ESI] + CF adc dword [edi],eax ; save the flags register to the stack, for the next iteration pushf ; these affect the CF, which is why it has to be saved to the stack add esi,4 add edi,4 add cx,4 ; cmp also affects the CF cmp cx,400 jl .SUB ; clean up the stack popf ret endp ; ------------------------------------------------------------------------------------- proc ShiftLeft uses edi ecx ; Shift dest number left by 1 bit ; address of dest number is in eax mov edi,eax ; start from the high order double word in the dest add edi,396 mov cx,396 .SHIFT: mov eax,dword [edi-4] shld dword [edi],eax,1 sub edi,4 sub cx,4 cmp cx,0 jg .SHIFT shl dword [edi],1 ret endp ; ------------------------------------------------------------------------------------- proc CopyBuffer uses esi edi ecx ; copy data from one 400 byte buffer to another ; address of source passed in EAX ; address of destination passed in EDX mov esi,eax mov edi,edx mov cx,400 .COPY: mov eax,[esi] mov [edi],eax inc esi inc edi dec cx jcxz .DONE jmp .COPY .DONE: ret endp ; ------------------------------------------------------------------------------------- proc IsZero uses esi ecx ; test a 400 byte value ; address passed in EAX mov esi,eax mov cx,400 ; the result is returned in AL xor al,al .CHECK_IF_0: cmp dword [esi],0 ; just quit if found to be non zero jne .QUIT sub cx,4 ; if cx reaches zero, the hex value is zero cmp cx,0 jle .IS_ZERO add esi,4 jmp .CHECK_IF_0 ; AL = true if the value is zero .IS_ZERO: mov al,1 .QUIT: ret endp ; ------------------------------------------------------------------------------------- proc Compare uses esi edi ecx ; compare two 400 byte unsigned integers A and B ; address of A passed in EAX ; address of B passed in EDX ; result is returned in AL ; if(A less than B) AL = 1 ; if(A equals B) AL = 2 ; if(A greater than B) AL = 4 mov edi,eax mov esi,edx ; start from the high order bytes add esi,396 add edi,396 mov cx,0 xor eax,eax .COMPARE: mov edx,dword [edi] cmp edx,dword [esi] ja .GREATER_THAN jb .LESS_THAN add cx,4 cmp cx,400 jge .EQUAL sub esi,4 sub edi,4 jmp .COMPARE .LESS_THAN: mov al,1 jmp .QUIT .EQUAL: mov al,2 jmp .QUIT .GREATER_THAN: mov al,4 .QUIT: ret endp ; ------------------------------------------------------------------------------------- section '.idata' import data readable writeable library kernel,'KERNEL32.DLL',\ user,'USER32.DLL' import kernel,\ GetModuleHandle,'GetModuleHandleA',\ ExitProcess,'ExitProcess' import user,\ DialogBoxParam,'DialogBoxParamA',\ SetDlgItemText,'SetDlgItemTextA',\ GetDlgItemText,'GetDlgItemTextA',\ EndDialog,'EndDialog' ; ------------------------------------------------------------------------------------- section '.data' readable writeable InputBuffer rb 400 Ten_N_Buffer rb 400 TempBuffer_1 rd 400 TempBuffer_2 rd 400 bfDisplay rb 4000 nInputChars dw 0 Digit db 0 Power_N dw 0 szInputInfoText db "Enter the input as a BIN, HEX or OCT number. Max number size = 400 bytes.",0 szOutputInfoText db "",0 ; ------------------------------------------------------------------------------------- section '.rc' resource data readable directory RT_DIALOG,dialogs resource dialogs,IDD_THE_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,the_dialog dialog the_dialog,\ 'Binary To Decimal',50,50,400,400,\ DS_MODALFRAME+WS_MINIMIZEBOX+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\ 0,0,"Lucida Console",11 dialogitem 'BUTTON','Input',-1,7,5,386,120,BS_GROUPBOX+WS_VISIBLE,0 dialogitem 'BUTTON',"Hex",-1,7,130,386,120,BS_GROUPBOX+WS_VISIBLE,0 dialogitem 'BUTTON',"Decimal",-1,7,255,386,120,BS_GROUPBOX+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_INPUT,13,17,375,100,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_HEX,13,142,375,100,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_OUTPUT,13,265,375,100,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'BUTTON',"Binary To Decimal",IDC_BTN_BIN_TO_DEC,7,380,80,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Hex To Decimal",IDC_BTN_HEX_TO_DEC,89,380,80,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Octal To Decimal",IDC_BTN_OCT_TO_DEC,171,380,80,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Decimal To Decimal",IDC_BTN_DEC_TO_DEC,253,380,80,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Clear",IDC_BTN_CLEAR,335,380,40,14,BS_PUSHBUTTON+WS_VISIBLE,0 enddialog ; ------------------------------------------------------------------------------------- ```