Can some tell me what is wrong with this MASM code?

  • SpinRite v6.1 Release #3
    Guest:
    The 3rd release of SpinRite v6.1 is published and may be obtained by all SpinRite v6.0 owners at the SpinRite v6.1 Pre-Release page. (SpinRite will shortly be officially updated to v6.1 so this page will be renamed.) The primary new feature, and the reason for this release, was the discovery of memory problems in some systems that were affecting SpinRite's operation. So SpinRite now incorporates a built-in test of the system's memory. For the full story, please see this page in the "Pre-Release Announcements & Feedback" forum.
    /Steve.
  • Be sure to checkout “Tips & Tricks”
    Dear Guest Visitor → Once you register and log-in please checkout the “Tips & Tricks” page for some very handy tips!

    /Steve.
  • BootAble – FreeDOS boot testing freeware

    To obtain direct, low-level access to a system's mass storage drives, SpinRite runs under a GRC-customized version of FreeDOS which has been modified to add compatibility with all file systems. In order to run SpinRite it must first be possible to boot FreeDOS.

    GRC's “BootAble” freeware allows anyone to easily create BIOS-bootable media in order to workout and confirm the details of getting a machine to boot FreeDOS through a BIOS. Once the means of doing that has been determined, the media created by SpinRite can be booted and run in the same way.

    The participants here, who have taken the time to share their knowledge and experience, their successes and some frustrations with booting their computers into FreeDOS, have created a valuable knowledgebase which will benefit everyone who follows.

    You may click on the image to the right to obtain your own copy of BootAble. Then use the knowledge and experience documented here to boot your computer(s) into FreeDOS. And please do not hesitate to ask questions – nowhere else can better answers be found.

    (You may permanently close this reminder with the 'X' in the upper right.)

coffeeprogrammer

Well-known member
Jul 19, 2021
155
15
Can someone tell me what is wrong with this code? I get error A2070: invalid instruction operands on line 80. It is MASM code largely written by OpenGPT. It should tell if a number is prime when it is done. OpenGPT did preatty well, but there where a few problem that i fixed, I don't know what the problem is here. Thanks.
 

Attachments

  • prime_console.zip
    1.4 KB · Views: 264
Can someone tell me what is wrong with this code? I get error A2070: invalid instruction operands on line 80. It is MASM code largely written by OpenGPT. It should tell if a number is prime when it is done. OpenGPT did preatty well, but there where a few problem that i fixed, I don't know what the problem is here. Thanks.
I asked ChatGPT to fix the code and here is what it provided:
The error "A2070: invalid instruction operands" is usually caused by a mismatch between the operands and the instruction being used. In this case, the error is occurring on line 80, which is the "div ecx" instruction.

To fix the error, you will need to make sure that the "ecx" register contains a valid value before executing the "div" instruction. You can do this by initializing the "ecx" register before the loop, or by making sure that the value in "ecx" is not modified inside the loop.

Here is the corrected version of the code:
Code:
; Include the necessary header files
include \masm32\include\masm32rt.inc
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc

; Use the Windows console API and the C runtime library
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

; function prototypes
; MyFunction PROTO, param1:DWORD, param2:DWORD :DWORD
atoi PROTO, string:PTR BYTE

; Declare the main function
.data
prompt db "Enter a number: ", 0
result db "The number is ", 0
prime db "prime", 0
not_primeS db "not prime", 0
number dd ?
hStdOut HANDLE ?
hStdIn HANDLE ?

.code

main proc
; Set up the console window
invoke AllocConsole
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov hStdOut, eax
invoke GetStdHandle, STD_INPUT_HANDLE
mov hStdIn, eax

; Print the prompt and read the input
invoke WriteConsole, hStdOut, addr prompt, sizeof prompt - 1, addr number, 0
invoke ReadConsole, hStdIn, addr number, 0, 0, 0

; Convert the input string to an integer
invoke atoi, addr number

; Check if the number is prime
mov ecx, eax ; Set the loop counter to the number
xor eax, eax ; Clear the EAX register
test ecx, ecx ; Test if ecx is zero
je not_prime ; If ecx is zero, jump to not_prime
.while ecx > 1
mov edx, 0 ; Clear the EDX register
div ecx ; Divide the number by the loop counter
cmp edx, 0 ; Check if the division has a remainder
je not_prime ; If the division has a remainder, the number is not prime
dec ecx ; Decrement the loop counter
.endw

; Print the result
invoke WriteConsole, hStdOut, addr result, sizeof result - 1, addr number, 0
invoke WriteConsole, hStdOut, addr prime, sizeof prime - 1, addr number, 0
jmp theexit

not_prime:
; Print the result
invoke WriteConsole, hStdOut, addr result, sizeof result - 1, addr number, 0
invoke WriteConsole, hStdOut, addr not_

It looks like the last line wasn't completed.
 
How did you ask it what was wrong, i don't know how to do that? I took about five or so different questions to get it to write this code.
 
Well I have simplified it down, the code below shows the problem OpenGPT does not seem to think there is a problem.

include \masm32\include\masm32rt.inc
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc

atoi PROTO var1: PTR BYTE

.data
number dd 'Hi', 0

.code
main proc
invoke atoi, addr number

invoke ExitProcess, 0
main endp
atoi proc var1: PTR BYTE
mov al, [var1] ; error A2070: invalid instruction operands
ret
atoi endp
end
 
Well after starting a fresh chat it seems to have found the problem:

include \masm32\include\masm32rt.inc
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc

atoi PROTO var1 :pTR BYTE

.data
number dd 'Hi', 0

.code
main proc
invoke atoi, addr number

invoke ExitProcess, 0
main endp
atoi proc var1: PTR BYTE
mov al, byte ptr [var1] ; FIXED - error A2070: invalid instruction operands - FIXED
ret
atoi endp
end


So I guess adding byte ptr fixed things, I am not a very good assembler programmer, if anyone want to add context to this problem please do, it will help me. I guess I will check if it runs as a whole program yet.
 
many times it basically said to me that there was nothing really wrong, when i pasted that simplified version that was only enough code for the problem and added a comment with the error the assembler was giving it seemed to figure it out. I knew it was something in this area, but I don't really know way pther than perhaps a [] might be 32bits, so the byte ptr to change back to 8. I wish i was not getting tried.
 
Ok, my internet was out for most of the day today. Yesterday I asked ChatGPT a lot of questions about assembly and that got my mind in that place. Today I tried to fix yesterday’s problem of a “atoi” function for masm assembly (atoi is a function in C++ at least that converts a ansii character to an integer). I started with what ChatGPT gave me (which looks nothing like this) and kept editing and debugging until I got it to work. It seems to work, but I wonder if a true assembly programmer could write it in tighter leaner code. So please, rate me as an assembly programmer. I actually do think there is a better way to do this, not sure how at this point. I tried to write like (tried) with the flow control rather than jumps and labels. Here it is:

Code:
include \masm32\include\masm32rt.inc

atoi PROTO string:PTR BYTE
strlength PROTO  pString: PTR BYTE

.data
value byte "5432",0

.code
start:
    call main

main proc
    invoke atoi, addr value   
    invoke ExitProcess, 0
main endp

atoi PROC string:PTR BYTE
    invoke strlength, string
    mov ecx, eax
    xor eax, eax
    xor ebx, ebx
    mov edx, dword ptr [string]
    
    .WHILE ecx != 0
        mov bl, byte ptr[edx]
        .IF (bl >= '0') && (bl <= '9')
            sub bl, '0'
            imul eax, 10
            movzx ebx, bl            ; this and
            add eax, ebx            ; this - is there a way to do this in one instruction???
        .ENDIF
        inc edx
        dec ecx
    .ENDW
    ret
atoi ENDP

strlength PROC USES edi, pString: PTR BYTE
    
    mov edi, pString
    mov eax, 0
    
    .WHILE byte ptr[edi] != 0
        inc edi
        inc eax
    .endw
    
    ret
strlength endp

end start
 
ChatGPT does make mistakes in assembly, but if you know a little about assembly you can fix them. I made a bouncing ball app masm program over a year ago, it was a mess and it was about 340 lines. I had chatGPT help me and I rewroteit for a v2 and it came out at 139 lines, there are two minor bugs that I know how to fix, but I wanted to post it. It seems to work. chatGPT helped a lot. Here it is:
Code:
.686p                       ; create 32 bit code
.model flat, stdcall        ; 32 bit memory model
option casemap :none        ; case sensitive

include windows.inc
include user32.inc
include kernel32.inc
include gdi32.inc
include masm32.inc
includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
includelib masm32.lib

WinMain PROTO :HINSTANCE, :HINSTANCE, :LPSTR, :DWORD

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?

.data
ClassName    db "bounce_v2",0
AppName        db "Bounce V2",0
ballX    dd    100
ballY    dd    100
ballRadius    dd 50
ballDirectionX    dd    1
ballDirectionY    dd    1

.const

.code
start:
    invoke GetModuleHandle, 0
    mov hInstance, eax   
    invoke GetCommandLine
    mov CommandLine, eax   
    invoke WinMain, hInstance, 0, CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess, eax
    
WinMain PROC hInst:HINSTANCE, hPrevInst:HINSTANCE, cmdLine:LPSTR, cmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND
    
    mov wc.cbSize, SIZEOF WNDCLASSEX
    mov wc.style, CS_HREDRAW or CS_VREDRAW
    mov wc.lpfnWndProc, OFFSET WndProc
    mov wc.cbClsExtra, 0
    mov wc.cbWndExtra, 0
    push hInstance
    pop wc.hInstance
    mov wc.hbrBackground, COLOR_WINDOW+1
    mov wc.lpszMenuName, 0
    mov wc.lpszClassName, OFFSET ClassName
    invoke LoadIcon, 0, IDI_APPLICATION
    
    mov wc.hIcon, eax
    mov wc.hIconSm, eax
    invoke LoadCursor, 0, IDC_ARROW
    mov wc.hCursor, eax
    invoke RegisterClassEx, addr wc
    
    invoke CreateWindowEx, 0, ADDR ClassName, ADDR AppName, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        0, 0, hInst, 0
        
    mov hwnd, eax
    invoke ShowWindow, hwnd, SW_SHOWNORMAL
    invoke UpdateWindow, hwnd

    invoke SetTimer, hwnd, 0, 1, 0
    
    .while TRUE
        invoke GetMessage, addr msg, NULL, 0, 0
        .BREAK .IF (!eax)
        invoke TranslateMessage, addr msg
        invoke DispatchMessage, addr msg
    .endw
    
    mov eax, msg.wParam
    ret
    
WinMain ENDP

WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    LOCAL ps:PAINTSTRUCT
    LOCAL rect:RECT
    
    .if uMsg == WM_CREATE

    .elseif uMsg == WM_PAINT
        invoke BeginPaint, hWnd, addr ps
        mov eax, ps.hdc
        mov ebx, ballX
        add ebx, 25
        mov ecx, ballY
        add ecx, 25   
        invoke Ellipse, eax, ballX, ballY, ebx, ecx
        invoke EndPaint, hWnd, addr ps
        mov eax, TRUE
        ret
        
    .elseif uMsg == WM_TIMER
        xor ebx, ebx
        mov ebx, ballDirectionX
        add ballX, ebx
        mov ebx, ballDirectionY
        add ballY, ebx   
        invoke GetClientRect, hWnd, addr rect
    
        mov ebx, rect.right
        .IF ballX < 0 || ballX > ebx
            neg ballDirectionX
        .ENDIF
            
        mov ebx, rect.bottom
        .IF ballY < 0 || ballY > ebx
            neg ballDirectionY
        .ENDIF
        
        invoke InvalidateRect, hWnd, NULL, TRUE
        mov eax, TRUE
        ret
    
    .elseif uMsg == WM_CLOSE

    .elseif uMsg == WM_DESTROY
        invoke PostQuitMessage,0
    
    .else
        invoke DefWindowProc, hWnd, uMsg, wParam, lParam
        ret
    .endif
        xor eax, eax
        ret
WndProc ENDP

end start