News:

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

Main Menu

64 bit errors

Started by shankle, September 14, 2012, 10:32:05 PM

Previous topic - Next topic

shankle

Made the changes you last suggested and the 1st screen still doesn't show.
The messagebox right after the "UpdateWindow" did NOT show.
The messagebox in WM_Create did show. Checking to see why the 1st
messagebox was bypassed. Think it is a sequence of events in windows
problem.

If GoBug doesn't debug 64-bit programs then I never need to run 64-bit
jcl for 64-bit programs. I did this not realizing GoBug was only a 32-bit
debugger.

japheth

Quote from: shankle on October 02, 2012, 07:32:01 AM
Checking to see why the 1st
messagebox was bypassed. Think it is a sequence of events in windows
problem.

Yes. WM_CREATE is send from inside CreateWindow(), so this is "the 1st".

Quote
If GoBug doesn't debug 64-bit programs then I never need to run 64-bit
jcl for 64-bit programs. I did this not realizing GoBug was only a 32-bit
debugger.

There are 64-bit debuggers: FDBG (written in FASM, has a GUI - it's advertised as AMD64 debugger, so I'm not 100% sure if it also works for Intel cpus), MS debuggers ( CDB, WinDbg ). Even if the debugger's user interface may be somewhat archaic - you can always code a hard breakpoint ( "int 3") in the assembly source, the debugger will stop and you can examine registers, see contents of variables, single-step, ....


   mov   D[wc.lpfnWndProc], OFFSET WndProc


You probably already changed the "D" to a "Q" ( pointers in Win64 are 64-bit ). That's better, but not perfect. It works as long as the address where the image is loaded is within the first 4 GB. The assembler cannot tell if this will be the case - the image base address is usually set by the linker. To make your code running in ALL cases, change it to:


   mov rax, OFFSET WndProc
   mov Q[wc.lpfnWndProc], rax


The reason for this weird necessity is a AMD64 peculiarity - it has only very limited support for 64-bit constants.


   invoke LoadIcon, NULL,IDI_APPLICATION
   mov   D[wc.hIcon], eax


All handles ( usually struct members beginning with a 'h' ) have been changed to 64-bit in Win64, so you'll have to change the second line to:


   mov   Q[wc.hIcon], rax


shankle

Thank you Japheth for your suggestions.
Will check them all out.
I saw your post on Jwasm in Ubuntu and didn't
think that Windows APIs would work in Linux.
Very interesting, most over my head, but maybe
when I have time, try to convert one of my programs
so that it will run on some Linux distro.


shankle

32-bit program is working.
64-bit program is not working.

WM_Create goes to the end of WM_Create then
Winmain executes to the UpdateWindow and the
screen appears.
WM_PAINT never executes.
Putting CS_HREDRAW/CS_VREDRAW in style has no effect.
Have a messagebox at the beginning of WM_PAINT and
it doesn't execute so I know it's not getting there.
Thanks for any suggestions.

qWord

you maybe show us you current code?
MREAL macros - when you need floating point arithmetic while assembling!

shankle

Thanks for responding qWord
Below is the code you requested.

        10-4-2012
#define LINKFILES
#define codejps
#define WIN64
#INCLUDE windows.h

DATA SECTION
BufAdd             dd       0
colorbk             dq       00ff0000h      ; blue
dwNeeded        dq       0
dwReturned      dq       0
hBrush             dq       0
hdcPrn             dq       0
hInstance        dq       0
holdleft           dd       0
holdright         dd       0
holdbottom     dd       0
holdtop           dd       0       
pinfo4            dq       0
savemiddleofX    dd       0

AppName            db   "blah1",0
datestring           db   "MM'-'dd'-'yyyy",0
szDisplayName    db   'wc',0
CommandLine LPSTR     ?

.code
start:
   invoke GetModuleHandleA, NULL
   mov    [hInstance],eax
   invoke GetCommandLine
   invoke WinMain, [hInstance],NULL,[CommandLine],SW_SHOWDEFAULT
;   invoke ExitProcess,rax  - GoAsm wants []
   invoke ExitProcess,[rax]
                   
WinMain:
    FRAME hInst,hPrevInst,CmdLine,CmdShow       
   LOCAL wc:WNDCLASSEXA,msg:MSG,hdc,rc:RECT,hWnd

   mov   D[wc.cbSize], SIZEOF WNDCLASSEXA
   mov   D[wc.style], CS_BYTEALIGNWINDOW
   mov   rax,offset WndProc   
   mov   Q[wc.lpfnWndProc],rax
   mov   D[wc.cbClsExtra], NULL
   mov   D[wc.cbWndExtra], NULL
   push  [hInst]
   pop   [wc.hInstance]
   invoke LoadIcon, NULL,IDI_APPLICATION
   mov   Q[wc.hIcon], rax
              invoke LoadCursor, NULL,IDC_ARROW   
              mov   Q[wc.hCursor], rax
   invoke CreateSolidBrush, [colorbk]          ; background color
              mov   Q[hBrush], rax
   mov   Q[wc.hbrBackground], rax
   mov   Q[wc.lpszMenuName], NULL
   mov   Q[wc.lpszClassName], OFFSET szDisplayName
   mov   Q[wc.hIconSm], 0
   
     invoke RegisterClassExA, addr wc
     invoke SystemParametersInfoA, SPI_GETWORKAREA,0,addr rc,0          
     mov eax,[rc.left]
     mov [holdleft], eax
     mov eax,[rc.right]
     mov [holdright],eax
     mov eax,[rc.bottom]
     mov [holdbottom],eax
     mov eax,[rc.top]
     mov [holdtop],eax     
     push edx             
     push ebx
     xor edx,edx     
     mov eax,[holdright]     
     mov ebx,2
     div ebx                     
     mov [savemiddleofX],eax   
     pop ebx
     pop edx
                 
; This code executed when turned on
; temp code begin   
;tmsg1            db 'got to end of winmain_cr',0
;        invoke MessageBox, [hWnd], addr tmsg1, addr tmsg1, MB_OK ;true
; temp code end       

   INVOKE CreateWindow, addr szDisplayName,addr AppName,\
         WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MAXIMIZEBOX|WS_MINIMIZEBOX,\
        [rc.left],[rc.top],[rc.right],[rc.bottom],NULL,NULL,[hInstance],NULL                   
;        mov   [hWnd],eax                                 
         mov   [hWnd],rax                                 

   invoke ShowWindow, [hWnd],SW_SHOWNORMAL
   invoke UpdateWindow, [hWnd]
; The above instruction executed and the screen appeared
; Then chaos.................            

; ===============================================================
;  Loop until PostQuitMessage is sent
; ===============================================================
L1:
INVOKE GetMessageA,addr msg,0,0,0
OR RAX,RAX              ;see if it is WM_QUIT
JZ >L2                  ;yes
INVOKE TranslateMessage,addr msg
INVOKE DispatchMessageA,addr msg
JMP L1                  ;after message dealt with, loop back for next one
L2:                     ;message was WM_QUIT
INVOKE UnregisterClassA   ;ensure class is removed
INVOKE ExitProcess,[msg.wParam]    ;wParam=exit code
ret

;      .StartLoop
;         INVOKE GetMessageA, addr msg,0,0,0
;;;          cmp eax,-1
;         or rax,rax   ; see if it is wm_quit
;          je >.ExitLoop
;          INVOKE TranslateMessage, addr msg
;          INVOKE DispatchMessageA, addr msg
;          jmp .StartLoop
;       .ExitLoop
;;;;          mov eax,[msg.wParam]         
;          mov rax,[msg.wParam]         
;          ret           
       ENDF
       
WndProc:
        FRAME hWnd,uMsg,wParam,lParam
        USES rbx,rdi,rsi
        Local hMemory,ps:PAINTSTRUCT,hdc
               
.WM_CREATE
        cmp D[uMsg],WM_CREATE
        jne >>.WM_CHAR       
        invoke GetDC, [hWnd]
        mov [hdc], rax             
        invoke  EnumPrinters, PRINTER_ENUM_LOCAL,NULL,4,NULL,\
                0,addr dwNeeded,addr dwReturned               
       invoke  GlobalAlloc, GHND,[dwNeeded]
       mov       [hMemory], rax
       invoke  GlobalLock, [rax]
       mov       [pinfo4],rax      
       invoke  EnumPrinters, PRINTER_ENUM_LOCAL,NULL,4,addr PrintCString,\
                                [dwNeeded],addr dwNeeded,addr dwReturned
        mov rbx,addr PrintCString
        mov rdx, [rbx+PRINTER_INFO_4.pPrinterName]
        invoke  CreateDC, NULL,rdx,NULL,NULL      
        mov       [hdcPrn],rax
        invoke  GlobalUnlock, [hMemory]   
        invoke  GlobalFree, [hMemory]                                                
        invoke Rectangle, [hdc],0,0,[holdright],[holdbottom]                    

; This code executed when turned on               
; temp code begin   
;tmsg2            db 'got to end of wm_create',0
;        invoke MessageBox, [hWnd], addr tmsg2, addr tmsg2, MB_OK ;true
; temp code end       

        xor rax,rax
        ret
       
.WM_CHAR         
        cmp D[uMsg],WM_CHAR 
        jne >>.WM_PAINT
;   other code
         ret
         
.WM_PAINT
        cmp D[uMsg],WM_PAINT
        jne >>.WM_DESTROY       

; This code never executes               
; temp code begin   
;tmsg3            db 'got wm_paint',0
        invoke MessageBox, [hWnd], addr tmsg3, addr tmsg3, MB_OK ;true
; temp code end       

qWord

- Why are using movable memory?
- For "mov rdx, [rbx+PRINTER_INFO_4.pPrinterName]", RBX seems to field with a wrong pointer.
- You should always check pointers after allocation (GlobalAlloc,HeapAlloc,...).

The following adaption works for me:
;#define LINKFILES
;#define codejps
#define WIN64
#INCLUDE headers\windows.h

DATA SECTION
    BufAdd          dd 0
    colorbk         dq 00ff0000h      ; blue
    pinfo4          dq 0
    hBrush          dq 0
    hdcPrn          dq 0
    hInstance       dq 0
    holdleft        dd 0
    holdright       dd 0
    holdbottom      dd 0
    holdtop         dd 0       
    savemiddleofX   dd 0
   
    AppName         db   "blah1",0
    datestring      db   "MM'-'dd'-'yyyy",0
    szDisplayName   db   'wc',0
    CommandLine     LPSTR ?

.code
start:
    and rsp,-16
    sub rsp,4*8
   invoke GetModuleHandleA, NULL
   mov    [hInstance],eax
   invoke GetCommandLine
   invoke WinMain, [hInstance],NULL,[CommandLine],SW_SHOWDEFAULT
   invoke ExitProcess,rax
WinMain: FRAME hInst,hPrevInst,CmdLine,CmdShow       
    LOCAL wc:WNDCLASSEXA,msg:MSG,hdc,rc:RECT,hWnd

    mov D[wc.cbSize], SIZEOF WNDCLASSEXA
    mov D[wc.style], CS_BYTEALIGNWINDOW | CS_HREDRAW | CS_VREDRAW
    mov rax,offset WndProc   
    mov Q[wc.lpfnWndProc],rax
    mov D[wc.cbClsExtra], NULL
    mov D[wc.cbWndExtra], NULL
    push [hInst]
    pop [wc.hInstance]
    invoke LoadIcon, NULL,IDI_APPLICATION
    mov Q[wc.hIcon], rax
    invoke LoadCursor, NULL,IDC_ARROW   
    mov Q[wc.hCursor], rax
    invoke CreateSolidBrush, [colorbk]          ; background color
    mov Q[hBrush], rax
    mov Q[wc.hbrBackground], rax
    mov Q[wc.lpszMenuName], NULL
    mov Q[wc.lpszClassName], OFFSET szDisplayName
    mov Q[wc.hIconSm], 0
   
    invoke RegisterClassExA, addr wc
    invoke SystemParametersInfoA, SPI_GETWORKAREA,0,addr rc,0         
    mov eax,[rc.left]
    mov [holdleft], eax
    mov eax,[rc.right]
    mov [holdright],eax
;   mov ebx,2   ;
;   div ebx     ; bad code !!!
    shr eax,1
    mov [savemiddleofX],eax   
    mov eax,[rc.bottom]
    mov [holdbottom],eax
    mov eax,[rc.top]
    mov [holdtop],eax     

    invoke CreateWindow, addr szDisplayName,addr AppName,\
    WS_VISIBLE|WS_OVERLAPPEDWINDOW,\
    [rc.left],[rc.top],[rc.right],[rc.bottom],NULL,NULL,[hInstance],NULL                   
    mov [hWnd],rax                                 
    invoke ShowWindow, [hWnd],SW_SHOWNORMAL
    invoke UpdateWindow, [hWnd]

L1: invoke GetMessage,addr msg,0,0,0
    test eax,eax
    JZ >L2
    cmp eax,-1
    je >L2
    invoke TranslateMessage,addr msg
    invoke DispatchMessage,addr msg
    JMP L1
L2:
    ret
ENDF
   
WndProc: FRAME hWnd,uMsg,wParam,lParam
    USES rbx,rdi,rsi
    Local ps:PAINTSTRUCT,hdc,dwNeeded:Q,dwReturned:Q,rect:RECT
   
    .WM_CREATE
        cmp D[uMsg],WM_CREATE
        jne >> .WM_DESTROY

        mov Q[dwNeeded],0 ; zero upper 32 Bits

        invoke GetDC, [hWnd]
        mov [hdc], rax             
        invoke  EnumPrinters, PRINTER_ENUM_LOCAL,NULL,4,NULL,0,addr dwNeeded,addr dwReturned               
        invoke GlobalAlloc,GPTR,[dwNeeded]
        test rax,rax
        jz >> .err@GlobalAlloc
        mov [pinfo4],rax
        invoke  EnumPrinters,PRINTER_ENUM_LOCAL,NULL,4,[pinfo4],[dwNeeded],addr dwNeeded,addr dwReturned
        mov rbx,[pinfo4]
        mov rdx, [rbx+PRINTER_INFO_4.pPrinterName]
        invoke CreateDC, NULL,rdx,NULL,NULL       
        mov [hdcPrn],rax
     
        invoke Rectangle, [hdc],0,0,[holdright],[holdbottom]       
        jmp >> .END

        .err@GlobalAlloc
            ; allocation error
            invoke ExitProcess,0
        jmp >> .END
    .WM_DESTROY
        cmp D[uMsg],WM_DESTROY
        jne >> .WM_PAINT
        invoke GlobalFree, [pinfo4]
        invoke PostQuitMessage,0   
        jmp >> .END
    .WM_PAINT
        cmp D[uMsg],WM_PAINT
        jne >> .DEFAULT
        invoke GetClientRect,[hWnd],addr rect
        invoke BeginPaint,[hWnd],addr ps
        mov rcx,rax
        mov rdx,[pinfo4]
        invoke DrawText,rcx,Q[rdx+PRINTER_INFO_4.pPrinterName],-1,addr rect,DT_CENTER
        invoke EndPaint,[hWnd],addr ps
        jmp >> .END
    .DEFAULT
        invoke DefWindowProc,[hWnd],[uMsg],[wParam],[lParam]
        ret
    .END
   
    xor rax,rax
    ret
ENDF
MREAL macros - when you need floating point arithmetic while assembling!

shankle

Thanks qWord.
Working on your solution. Later I might have a few
questions. Just wanted to let you know I was not
ignoring your solution.

shankle

        10-7-2012
Program still errors out after painting the 1st screen.
I feel that it is some register change that I can not see in GoAsm.
Have no debugger to help me.
In MASM32 I avoided the stack like the plague. Only used it for
push/pop, pushad\popad. Savregx was much easier to follow.
So I do not really understand what "and rsp,-16 and sub rsp, 4*8"
are doing. I know that GoAsm adds rcx,rdx,r8 and R9 to the stack
but that is as far as I get at the present time in my learning curve.

In L1 what is cmp eax,-1 doing?
I noticed that you put GlobalFree in WM_DESTROY but did not use
GlobalLock in WM_CREATE. Is that OK??
Don't know how to do the fancy scroll goodie that you did.
Thanks for your help qWord       
       
#define LINKFILES
#define codejps
#define WIN64
#INCLUDE windows.h

DATA SECTION
colorbk              dq       00ff0000h      ; blue
dwNeeded         dq       0
dwReturned       dq       0
hBrush              dq       0
hdcPrn              dq       0
hInstance          dq       0
pinfo4               dq       0

BufAdd             dd       0
holdleft            dd       0
holdright          dd       0
holdbottom       dd       0
holdtop            dd       0       
savemiddleofX  dd       0

AppName            db   "blah1",0
datestring           db   "MM'-'dd'-'yyyy",0
szDisplayName    db   'wc',0
CommandLine LPSTR     ?

.code
start:
    and rsp,-16
    sub rsp,4*8
   invoke GetModuleHandleA, NULL
   mov    [hInstance],eax
   invoke GetCommandLine
   invoke WinMain, [hInstance],NULL,[CommandLine],SW_SHOWDEFAULT
   invoke ExitProcess,rax
                   
WinMain:
    FRAME hInst,hPrevInst,CmdLine,CmdShow       
   LOCAL wc:WNDCLASSEXA,msg:MSG,hdc,rc:RECT,hWnd

   mov   D[wc.cbSize], SIZEOF WNDCLASSEXA
   mov   D[wc.style], CS_BYTEALIGNWINDOW | CS_HREDRAW | CS_VREDRAW
   mov   rax,offset WndProc   
   mov   Q[wc.lpfnWndProc],rax
   mov   D[wc.cbClsExtra], NULL
   mov   D[wc.cbWndExtra], NULL
   push  [hInst]
   pop   [wc.hInstance]
   invoke LoadIcon, NULL,IDI_APPLICATION
   mov   Q[wc.hIcon], rax
    invoke LoadCursor, NULL,IDC_ARROW   
    mov   Q[wc.hCursor], rax
   invoke CreateSolidBrush, [colorbk]          ; background color
    mov   Q[hBrush], rax
   mov   Q[wc.hbrBackground], rax
   mov   Q[wc.lpszMenuName], NULL
   mov   Q[wc.lpszClassName], OFFSET szDisplayName
   mov   Q[wc.hIconSm], 0
   
   invoke RegisterClassExA, addr wc
    invoke SystemParametersInfoA, SPI_GETWORKAREA,0,addr rc,0          
     mov eax,[rc.left]
     mov [holdleft], eax
     mov eax,[rc.right]
     mov [holdright],eax
     shr eax,1
     mov [savemiddleofX],eax       
     mov eax,[rc.bottom]
     mov [holdbottom],eax
     mov eax,[rc.top]
     mov [holdtop],eax     
                 
; This code executed when turned on
; temp code begin   
;tmsg1            db 'got to end of winmain_cr',0
;        invoke MessageBox, [hWnd], addr tmsg1, addr tmsg1, MB_OK ;true
; temp code end       

   INVOKE CreateWindow, addr szDisplayName,addr AppName,\
         WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MAXIMIZEBOX|WS_MINIMIZEBOX,\
        [rc.left],[rc.top],[rc.right],[rc.bottom],NULL,NULL,[hInstance],NULL                   
         mov   [hWnd],rax                                 

   invoke ShowWindow, [hWnd],SW_SHOWNORMAL
   invoke UpdateWindow, [hWnd]
; The above instruction executed and the screen appeared

L1:
    INVOKE GetMessageA,addr msg,0,0,0
    test eax,eax     ;see if it is WM_QUIT
    jz >L2           ;yes
    cmp eax,-1
    je >L2

    INVOKE TranslateMessage,addr msg
    INVOKE DispatchMessageA,addr msg
    jmp L1              ;after message dealt with, loop back for next one
L2:                     ;message was WM_QUIT
    ret
ENDF   

       
WndProc:
        FRAME hWnd,uMsg,wParam,lParam
        USES rbx,rdi,rsi
        Local hMemory,ps:PAINTSTRUCT,hdc
               
.WM_CREATE
        cmp D[uMsg],WM_CREATE
        jne >>.WM_CHAR       
        mov Q[dwNeeded],0             
        invoke GetDC, [hWnd]
        mov [hdc], rax
        invoke  EnumPrinters, PRINTER_ENUM_LOCAL,NULL,4,NULL,\
                0,addr dwNeeded,addr dwReturned               
       invoke  GlobalAlloc, GPTR,[dwNeeded]
       test    rax,rax
       jz >>.err@GlobalAlloc
          mov       [hMemory], rax
       invoke  GlobalLock, rax
       mov       [pinfo4],rax      
       invoke  EnumPrinters, PRINTER_ENUM_LOCAL,NULL,4,[pinfo4],\
                                [dwNeeded],addr dwNeeded,addr dwReturned
        mov rbx,[pinfo4]
        mov rdx, [rbx+PRINTER_INFO_4.pPrinterName]
        invoke  CreateDC, NULL,rdx,NULL,NULL      
       mov       [hdcPrn],rax
       invoke  GlobalUnlock, [hMemory]   
        invoke Rectangle, [hdc],0,0,[holdright],[holdbottom]                    

; This code executed when turned on               
; temp code begin   
;tmsg2            db 'got to end of wm_create',0
;        invoke MessageBox, [hWnd], addr tmsg2, addr tmsg2, MB_OK ;true
; temp code end       
        jmp >>.END
.err@GlobalAlloc
;    allocation error
         invoke ExitProcess,0
         jmp >>.END               
       
.WM_CHAR         
        cmp D[uMsg],WM_CHAR 
        jne >>.WM_PAINT
        jmp >>.END
         
.WM_PAINT
        cmp D[uMsg],WM_PAINT
        jne >>.WM_DESTROY       

; This code never executes               
; temp code begin   
;tmsg3            db 'got wm_paint',0
        invoke MessageBox, [hWnd], addr tmsg3, addr tmsg3, MB_OK ;true
; temp code end
        jmp >>.END

.WM_DESTROY
        cmp D[uMsg],WM_DESTROY
         jne >.default   
                         
       invoke  GlobalUnlock, [hMemory]     
       invoke  GlobalFree, [hMemory]                                                                             
        invoke ReleaseDC,[hWnd],[hdc]
        invoke PostQuitMessage,NULL
        jmp >>.END
.default
      invoke DefWindowProc,[hWnd],[uMsg],[wParam],[lParam]
       ret
.END
        xor rax, rax
        ret          
ENDF                 

qWord

Quote from: shankle on October 08, 2012, 12:17:54 AMSo I do not really understand what "and rsp,-16 and sub rsp, 4*8"
are doing.
Sorry, I did forget to remove these two instructions: They should align the stack to 16 and allocated the shadow space for the first 4 calling parameter (FASTCALL calling convention). This is not needed, because GoAsm's INVOKE directive does this allready.
Quote from: shankle on October 08, 2012, 12:17:54 AMIn L1 what is cmp eax,-1 doing?
If GetMessage() fails, it returns -1.
Quote from: shankle on October 08, 2012, 12:17:54 AMI noticed that you put GlobalFree in WM_DESTROY but did not use
GlobalLock in WM_CREATE. Is that OK??
1. GlobalLock/Unlock is only needed, if you have an movable memory object - the example works with fixed memory -> GlobalAlloc() returns a pointer instead of a handle. In fact, there is no reason to use movable memory, except that an API requires it (e.g. clip board operation).
2. The freeing is done in WM_DESTROY because the memory is used in WM_PAINT
Quote from: shankle on October 08, 2012, 12:17:54 AMDon't know how to do the fancy scroll goodie that you did.
Which scroll goodie?
MREAL macros - when you need floating point arithmetic while assembling!

wjr

Actually, more like the code at WM_PAINT is always executing... you return that you have processed the message, but you have not called BeginPaint and EndPaint (as qWord did), so the region does not get validated and you get another WM_PAINT request, over and over again...

Also, if you are going to use hMemory and hdc in WM_DESTROY, you will need to switch those variables from LOCAL to your DATA section (they will not be the same as they were while processing WM_CREATE).

Try Pelles C debugger mentioned in the other thread. Instead of MessageBox, you could use something like
INVOKE OutputDebugString, "Got to this point"

shankle

#26
Thank you WJR.
The problem has been solved.
I was assuming that the error was prior to WM_PAINT
because my messagebox did NOT execute.
Anyway here is the offending instruction in WM_PAINT:
     FTS  db  0
    cmp B[FTS],0
    je >. blah1
    jmp >>.blah2
It took the branch to blah2 instead of blah1.
This is just info about why I was having all my problems.
Thanks for all your patience

shankle

                 10-12-2012
                                 
This code is for a 64-bit program.                 
purpose is to convert #s in spn to a string in hpn3
spn #s run like 1,2,3,4,5 etc. no sign involved.
hpn3 numbers convert to #01,#02,#03,#04 etc.
Needless to say it's not working in 64-bit GoAsm.
Almost the same code works in MASM32 and 32-bit GoAsm.

BufAdd      dd   0
spn         db   1
hpn3        db   "   ",0

       CALL Converter
                       
;other code       
Converter:     
;   edx  spn is the input field
;   ebx  hpn3 is the output field   
       lea ebx,hpn3     
       inc ebx                        ; save 1st byte for # sign
       mov [BufAdd],ebx
       xor edx,edx
       mov dl,B[spn]      ; input
       invoke dwtoa, edx,[BufAdd]    ; output is in hpn3                                   
       cmp B[hpn3+1],030h
        jge >
         mov B[hpn3+1],020h
:       
       mov B[hpn3],023h             ; # sign in front of number       
       inc B[spn]                   ; next input number
       ret
       
; other code       
; DWTOA is from MASM32
dwtoa:
     FRAME dwValue,lpBuffer
     USES esi,edi
   
    ; -------------------------------------------------------------
    ; convert DWORD to ascii string
    ; dwValue is value to be converted
    ; lpBuffer is the address of the receiving buffer
    ; EXAMPLE:
    ; invoke dwtoa,edx,addr buffer
    ;
    ; Uses: eax, ecx, edx.
    ; -------------------------------------------------------------
      mov   eax,[dwValue]
      mov edi,[lpBuffer]

      test eax, eax         ; is the value negative
      jns >
      mov B[edi], '-'         ; store a minus sign
      inc edi
      neg eax              ; and invert the value
:
      mov esi, edi           ; save pointer to first digit
      mov ecx, 10
.convert
      test eax,eax           ; while there is more to convert   
      jz >
      xor edx, edx
      div ecx              ; put next digit in edx
      add dl, '0'           ; convert to ASCII
      mov [edi],dl           ; store it
      inc edi
      jmp <.convert
:   
     mov B[edi], 0          ; terminate the string

.reverse                    ; We now have all the digits,
                            ; but in reverse order.
      cmp esi,edi
      jae >
      dec edi
      mov al,[esi]
      mov ah,[edi]
      mov [edi],al
      mov [esi],ah
      inc esi
      jmp <.reverse
:
    ret   
ENDF

wjr

Try changing BufAdd to DQ and in Converter use ecx instead of edx...

shankle

Thanks to all that helped.
The 64-bit program is now working except for a few cosmetic
refinements.

I don't understand the reasoning behind using an 8 byte field to
handle a 1 byte field. I thought I was excessive by using a 4 byte
field to handle 1 byte. But this is 64-bit code and what do I know.