News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Binary to displayable text, any base

Started by ahsat, March 31, 2024, 04:37:00 AM

Previous topic - Next topic

ahsat

Quote from: jj2007 on April 05, 2024, 05:55:38 AMWith that option, you can use mov edi, offset somestring. /LARGEADDRESSAWARE:NO means "stick to the 32-bit world, even in 64-bit code".
I don't know. But I came here to learn 64 bit, so I am stuck with whatever exists.

ahsat

#61
Thanks to jimg, I have a new routine, that is universally callable. It now checks the paramaters, saves and restores registers. The program now uses tabs instead of spaces.

I used the following link command to create the program:
polink.exe /SUBSYSTEM:CONSOLE /LARGEADDRESSAWARE:NO /ENTRY:main /OUT:AnyBase.exe AnyBase.obj


TITLE AnyBase

OPTION PROC:PRIVATE ;Don't automatically make procs public

include \masm64\include64\masm64rt.inc

cr equ 13
lf equ 10

.data

result db 65 dup (?) ;max should be 64, plus a null     
newLine db cr, lf, 0 ;cr and lf
numb qword ? ;holds the number being converted

.CODE

;Got to keep the Sumerian happy, base 60 is the max here.
digits db '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx'
maxBase equ $-digits ;Max base number, should be 60

bin2any proc theNumber:qword,
theBase:qword,
theDestination:qword
;----------------------------------------------------------------------------
; Original by Ray Gwinn
; Any binary number to any base.
;----------------------------------------------------------------------------
;
push rbx ;save regs, still can't get uses to work
push rcx
push rdi

mov rdi, theDestination ;destination addr to rdi
mov rbx, theBase ;the desired base to rbx
mov rax, 1 ;rax=1
cmp rbx, rax ;test if valid base
jbe short bin30 ;br if invalid base

cmp rbx, maxBase ;test if base too large
ja short bin30 ;br if base too large

mov rax, theNumber ;get the number to rax
xor ecx, ecx ;zero rcx

@@: push rdx ;save rdx, or a digit
inc rcx ;bump count of loops
xor edx, edx ;zero rdx
div rbx ;generate next digit in rdx
test rax, rax ;test if done
jnz @b ;loop if not done

@@: mov al, digits[rdx] ;get the ascii value
stosb ;save it
pop rdx ;restore rdx, or get next digit
loop @b ;loop till all digits processed

xor eax, eax ;no error
bin30: mov byte ptr [rdi], 0 ;null terminate the string
pop rdi ;restore regs, need for uses to work
pop rcx
pop rbx
ret
bin2any endp

main proc  Public
;----------------------------------------------------------------------------
; Program to demo any number to any base, bases 2 to 60.
;----------------------------------------------------------------------------
;
mov rax, 123456789 ;the number to display
mov numb, rax ;save it in numb
jmp @f

m00 db cr, lf, 'This is the number we will be converting', cr, lf, 0
@@: invoke bin2any, numb, 10, addr result

invoke StdOut, addr m00
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m04 db cr, lf, 'This is the 64 bit number, in hex', cr, lf, 0
@@: invoke bin2any, numb, 16, addr result

invoke StdOut, addr m04
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m05 db    cr, lf, 'This is the 64 bit number, in binary', cr, lf, 0
@@: invoke bin2any, numb, 2, addr result

invoke StdOut, addr m05
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m06 db cr, lf, 'In Sumerian Sexagesimal, base 60', cr, lf, 0
@@: invoke bin2any, numb, 60, addr result

invoke StdOut, addr m06
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m07 db cr, lf, 'In Aztec, Myan and Kaktovik, base 20', cr, lf, 0
@@: invoke bin2any, numb, 20, addr result

invoke StdOut, addr m07
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m08 db cr, lf, 'In Kaktovik, base 5', cr, lf, 0
@@: invoke bin2any, numb, 5, addr result

invoke StdOut, addr m08
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m09 db cr, lf, 'In Ternary, base 3', cr, lf, 0
@@: invoke bin2any, numb, 3, addr result

invoke StdOut, addr m09
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m10 db cr, lf, 'In Quaternary, base 4', cr, lf, 0
@@: invoke bin2any, numb, 4, addr result

invoke StdOut, addr m10
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m11 db cr, lf, 'In Undecimal, base 11', cr, lf, 0
@@: invoke bin2any, numb, 11, addr result

invoke StdOut, addr m11
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

@@: invoke ExitProcess, 0 ;Error code 0
ret

main endp

end

NoCforMe

Nice.

Still curious why you chose to use "abcdefghijkylmnop" as your Sumerian digits. Wouldn't that be confusing to any Sumerians trying to interpret your results?
Assembly language programming should be fun. That's why I do it.

ahsat

Quote from: NoCforMe on April 05, 2024, 08:10:02 AMStill curious why you chose to use "abcdefghijkylmnop"
Its a typo, I will correct it. It has been corrected in the post. Thank you, sometimes its hard to get my attention.

ahsat

The 32 bit version of Anybase, and uses works there.

I used the following link command:
polink.exe /SUBSYSTEM:CONSOLE /OUT:AnyBase32.exe AnyBase.obj

TITLE AnyBase

OPTION PROC:PRIVATE ;Don't automatically make procs public

include \masm32\include\masm32rt.inc

cr equ 13
lf equ 10

.data

result db 33 dup (?) ;max should be 32, plus a null     
newLine db cr, lf, 0 ;cr and lf
numb dword ? ;holds the number being converted

.CODE

;Got to keep the Sumerian happy, base 60 is the max here.
digits db '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx'
maxBase equ $-digits ;Max base number, should be 60

bin2any proc public uses ebx ecx edi,
theNumber:dword,
theBase:dword,
theDestination:dword
;----------------------------------------------------------------------------
; Original by Ray Gwinn
; Any binary number to any base.
;----------------------------------------------------------------------------
;
mov edi, theDestination ;destination addr to edi
mov ebx, theBase ;the desired base to ebx
mov eax, 1 ;eax=1
cmp ebx, eax ;test if valid base
jbe short bin30 ;br if invalid base

cmp ebx, maxBase ;test if base too large
ja short bin30 ;br if base too large

mov eax, theNumber ;get the number to eax
xor ecx, ecx ;zero ecx

@@: push edx ;save edx, or a digit
inc ecx ;bump count of loops
xor edx, edx ;zero edx
div ebx ;generate next digit in edx
test eax, eax ;test if done
jnz @b ;loop if not done

@@: mov al, digits[edx] ;get the ascii value
stosb ;save it
pop edx ;restore edx, or get next digit
loop @b ;loop till all digits processed

xor eax, eax ;no error
bin30: mov byte ptr [edi], 0 ;null terminate the string
ret
bin2any endp

entry_point proc public
;----------------------------------------------------------------------------
; Program to demo any number to any base, bases 2 to 60.
;----------------------------------------------------------------------------
;
mov eax, 123456789 ;the number to display
mov numb, eax ;save it in numb
jmp @f

m00 db cr, lf, 'This is the number we will be converting', cr, lf, 0
@@: invoke bin2any, numb, 10, addr result

invoke StdOut, addr m00
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m04 db cr, lf, 'This is the 32 bit number, in hex', cr, lf, 0
@@: invoke bin2any, numb, 16, addr result

invoke StdOut, addr m04
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m06 db cr, lf, 'In Sumerian Sexagesimal, base 60', cr, lf, 0
@@: invoke bin2any, numb, 60, addr result

invoke StdOut, addr m06
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m07 db cr, lf, 'In Aztec, Myan and Kaktovik, base 20', cr, lf, 0
@@: invoke bin2any, numb, 20, addr result

invoke StdOut, addr m07
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m08 db cr, lf, 'In Kaktovik, base 5', cr, lf, 0
@@: invoke bin2any, numb, 5, addr result

invoke StdOut, addr m08
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m09 db cr, lf, 'In Ternary, base 3', cr, lf, 0
@@: invoke bin2any, numb, 3, addr result

invoke StdOut, addr m09
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m10 db cr, lf, 'In Quaternary, base 4', cr, lf, 0
@@: invoke bin2any, numb, 4, addr result

invoke StdOut, addr m10
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

m11 db cr, lf, 'In Undecimal, base 11', cr, lf, 0
@@: invoke bin2any, numb, 11, addr result

invoke StdOut, addr m11
invoke StdOut, addr result
invoke StdOut, addr newLine
jmp @f

@@: invoke ExitProcess, 0 ;Error code 0
ret

entry_point endp

end entry_point

sinsi

USES still works with ML64 but only with the default prologue/epilogue. I guess that MASM64's prologue doesn't bother.
Windows 11 is better :tongue: but 98SE was the bee's knees

ahsat

Quote from: sinsi on April 05, 2024, 09:16:02 AMuses still works with ML64 but only with the default prologue/epilogue.
Can you show me in an example with code? I am sorry to be so behind and slow.

jj2007

Quote from: ahsat on April 05, 2024, 10:00:10 AMI am sorry to be so behind and slow

You are remarkably fast for your age, Ray. Truth is that 64-bit code is a can of worms. The PROLOGUE macro determines what happens when you write e.g. MyAlgo proc param1, the EPILOGUE macro specifies what the "instruction" ret does (it is a macro, yeah).

In 32-bit land, uses esi simply pushes esi on entry into the proc and pops it before the ret.

I bet that 90% of our members here (sinsi excluded) don't know what uses rsi does in 64-bit code. I had to set up a 64-bit test with ml64 and launch the debugger to find out. Here is the code:
include \masm64\include64\masm64rt.inc
.code
MyAlgo proc uses rsi arg1, arg2
  ret
MyAlgo endp
entry_point proc
Local pContent:QWORD, ticks:QWORD        ; OPT_Assembler ml64
  lea rax, entry_point
  conout "The entry point is at ", hex$(rax), lf
  int 3
  invoke MyAlgo, 123h, 456h
  invoke ExitProcess, 0                        ; terminate process
entry_point endp
end

The int 3 makes the debugger stop there. When hitting F7, you see the following on entry to MyAlgo:
0000000140001069     | 48:C7C1 23010000                | mov rcx,123               |
0000000140001070     | 48:C7C2 56040000                | mov rdx,456               |
0000000140001077     | E8 84FFFFFF                     | call <sub_140001000>      |
...
0000000140001000 <su | C8 8000 00                      | enter 80,0                |
0000000140001004     | 48:83EC 60                      | sub rsp,60                |
0000000140001008     | 48:894D 10                      | mov [rbp+10],rcx          |
000000014000100C     | 48:8955 18                      | mov [rbp+18],rdx          |
0000000140001010     | C9                              | leave                     |
0000000140001011     | C3                              | ret                       |

Do you see any attempt to save rsi? I don't.

ahsat

Quote from: jj2007 on April 05, 2024, 10:21:25 AMI would have to set up a 64-bit test with ml64 and launch the debugger to find out.
I have, and it does nothing, zip. No pushes or pops of anything with "uses esi".

I understand what you guys are saying about 32 bit is still better to write programs with. But I want to know what Intel is selling in their 64 bit products, as well as possibility developing a few programs. So, I want to use 64 bit, if for nothing else, to learn what it does.

sinsi

Previously...

I'm pretty sure that include \masm64\include64\masm64rt.inc also includes a custom prologue.
Windows 11 is better :tongue: but 98SE was the bee's knees

NoCforMe

Quote from: jj2007 on April 05, 2024, 10:21:25 AMinclude \masm64\include64\masm64rt.inc
.code
MyAlgo proc uses rsi arg1, arg2
  ret
MyAlgo endp
entry_point proc
Local pContent:QWORD, ticks:QWORD        ; OPT_Assembler ml64
  lea rax, entry_point
  conout "The entry point is at ", hex$(rax), lf
  int 3
  invoke MyAlgo, 123h, 456h
  invoke ExitProcess, 0                        ; terminate process
entry_point endp
end

0000000140001069    | 48:C7C1 23010000                | mov rcx,123              |
0000000140001070    | 48:C7C2 56040000                | mov rdx,456              |
0000000140001077    | E8 84FFFFFF                    | call <sub_140001000>      |
...
0000000140001000 <su | C8 8000 00                      | enter 80,0                |
0000000140001004    | 48:83EC 60                      | sub rsp,60                |
0000000140001008    | 48:894D 10                      | mov [rbp+10],rcx          |
000000014000100C    | 48:8955 18                      | mov [rbp+18],rdx          |
0000000140001010    | C9                              | leave                    |
0000000140001011    | C3                              | ret                      |

Do you see any attempt to save rsi? I don't.

It's AI,man; the assembler is so smart it knows you haven't touched RSI so it doesn't bother saving and restoring it. It's a mind reader.
Assembly language programming should be fun. That's why I do it.

zedd151

masm64 uses "USING" (not uses) reg... and the SaveRegs/RestoreRegs  macros for saving and restoring registers.

64 bit Stackframe register preservation macros
:skrewy:

ahsat

Quote from: sinsi on April 05, 2024, 10:45:21 AMI'm pretty sure that include \masm64\include64\masm64rt.inc also includes a custom prologue.
Okay, that's great. Can you show me how to use it with code? It does not seem to work for me in Anybase.

ahsat

Quote from: NoCforMe on April 05, 2024, 11:08:33 AMIt's AI,man; the assembler is so smart it knows you haven't touched RSI so it doesn't bother saving and restoring it. It's a mind reader.
I just made sure for myself, and that is not true.

ahsat