News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Help with console output

Started by TBRANSO1, November 30, 2018, 04:24:05 AM

Previous topic - Next topic

TBRANSO1

I am still learning to use MASM.  I am using the 64 bit VS version.  I have designed a couple of functions to read from and print to console

BTW I am calling the MASM functions with the proper extern "C" statements, from a C++ main for now.

I was wondering if someone could help with the output.

(FORGIVE ME, I WANTED TO INSERT AN IMAGE, BUT CAN'T FIGURE OUT HOW)
COMMANDLINE OUTPUT>
Hello, Tom, from VS2017 MASM64 - prints first
Hi there, VS2017 MASM64, thank you! - I enter some input
Hi there, VS2017 MASM        k you! - echos input to screen

My issue is that if I wrote less than the number of bytes where the part where it skips, it prints normally, it does this when it is more than 20 or so characters.  I have allocated a buffersize of 64 bytes. so it should be fine.

I am using WinAPI, ReadFile and WriteFile, here is my code:
; *************************************************************************
; MASM32 proto types for Win32 functions and structures
; ************************************************************************* 
;include c:\masm32\include\kernel32.inc
;include c:\masm32\include\masm32.inc

; *************************************************************************
; MASM32 object libraries
; ************************************************************************* 
includelib c:\masm32\lib\masm32.lib
includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib
includelib Kernel32.lib

extern MessageBoxA: proc
extern CreateThread: proc
extern WriteFile: proc
extern ReadFile: proc
extern GetStdHandle: proc

MAX_SIZE equ 10
STR_LEN equ sizeof hello
BUF_LEN equ 40h
STD_INPUT_HANDLE equ -10
STD_OUTPUT_HANDLE equ -11
INVALID_HANDLE_VALUE equ -1

.data
mybyte1 db 4
mybyte2 db 1
mutex dword 0 ; mutex
BytesWritten dword 0
BytesToRead dword 0
hello db "Hello, Tom, from VS2017 MASM64", 13, 10
shit db "SHITHEAD!", 0
name_prompt db "Please type your name: %c", 10, 0
out_msg db "Your name in capitals is ", 0

.data?
array db ?
mynum qword ?
num dword ?
shifter qword ?
hFile qword ?
my_name db ?

.code

PrintString MACRO string, size, readLen
    ; https://blogs.msdn.microsoft.com/oldnewthing/20160623-00/?p=93735
    sub rsp, 40                 ; Shadow space (4 * 8) & 1 parameter (8 bytes)
    ; https://docs.microsoft.com/en-us/cpp/build/stack-allocation
    and spl, -16                ; Align to 16

    ; https://msdn.microsoft.com/library/windows/desktop/ms683231.aspx
    mov ecx, STD_OUTPUT_HANDLE  ; DWORD nStdHandle = STD_OUTPUT_HANDLE
    call GetStdHandle           ; Call WinApi
    mov hFile, rax              ; Save returned handle

    mov bl, 1 ; Set ZF = 1

    ; https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-writefile
; BOOL WINAPI WriteFile(
    mov rcx, hFile              ; HANDLE        hFile (here: Stdout)
    lea rdx, string             ; LPCVOID       lpBuffer
    lea r9, readLen         ; LPDWORD       lpNumberOfBytesWritten
    mov r8d, size ; DWORD         nNumberOfBytesToWrite
    mov qword ptr [rsp+32], 0   ; LPOVERLAPPED  lpOverlapped = NULL
    call WriteFile              ; Call WinAPI
; );
   test bl, al ; test ZF for errors
   mov readLen, 0 ; Zero out the variable for reuse

   ; https://msdn.microsoft.com/library/windows/desktop/ms682658.aspx
   xor rcx, rcx                ; Set RCX / Close HANDLE
   add rsp, 40
   ret
endm

getCmdLineInput proc
; https://blogs.msdn.microsoft.com/oldnewthing/20160623-00/?p=93735
        sub rsp, 40                 ; Shadow space (4 * 8) & 1 parameter (8 bytes)
    ; https://docs.microsoft.com/en-us/cpp/build/stack-allocation
        and spl, -16                ; Align to 16

       mov ecx, STD_INPUT_HANDLE   ; DWORD nStdHandle = STD_INPUT_HANDLE
       call GetStdHandle           ; Call WinApi
       mov hFile, rax              ; Save returned handle

       mov bl, 1 ; Set ZF = 1

; https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-readfile
; BOOL ReadFile(
mov rcx, hFile ;   HANDLE       hFile,
lea rdx, array ;   LPVOID       lpBuffer,
mov r8d, BUF_LEN ;   DWORD        nNumberOfBytesToRead,
lea r9, BytesWritten ;   LPDWORD      lpNumberOfBytesRead,
mov qword ptr [rsp+32], 0 ;   LPOVERLAPPED lpOverlapped
call ReadFile ; Call WinAPI
; );

test bl, al ; test ZF for errors

        xor rcx, rcx                ; Set RCX / Close HANDLE
add rsp, 40

PrintString array, BytesWritten, BytesToRead

ret
getCmdLineInput endp


I have a question about macros... do you typically put in the full code with the ret?

I haven't finished error checking, as for testing for errors, like invalidHandle (-1)... is that correct using the test, then a jz or jne?

Thanks

PS: I realized after I wrote this, that it may be in the wrong forum... Admin, please feel free to put it where it goes.

aw27

Sorry, I landed here from Mars, so my question may sound weird.

What is VS2017 MASM64? Why are you mixing 32-bit libraries with 64-bit code? Where is the entry point of your program?

TBRANSO1

Quote from: AW on November 30, 2018, 05:08:18 AM
What is VS2017 MASM64? Why are you mixing 32-bit libraries with 64-bit code? Where is the entry point of your program?


Visual Studio 2017 masm64 just refers to using masm 64bit with ML64.exe compiler.  Entry is mentioned above in a C++ main. I am using 64 bit, b/c I can, and I also am creating algos to crunch large numbers.

aw27

Looks interesting your logic as well as omitting part of the answers. You did not explain the reason for 32-bit libraries.
Btw, a macro is not a function, what the hell makes you think it is something needing a ret?

hutch--

You are mixing 32 and 64 bit code which will never work as the two OS versions have different architecture. The code you posted is basically 32 bit code and you would build that with the 32 bit version of MASM, ML.EXE.

> extern MessageBoxA: proc

This type of prototyping would almost work in 64 bit but in 32 bit you must construct the prototypes differently.

MessageBox PROTO :DWORD,:DWORD,:DWORD,:DWORD

What is recommended is you use the supplied include files for 32 bit MASM code unless you want to write your own set if you have a couple of years to spend doing it.

Have a look at the "masm32rt.inc" file for 32 bit as it saves you from having to write prototypes for API code. In 32 bit you will have to write your own prototypes for your own procedures.

Now 64 bit MASM is a really different animal, its designed as a professional tool only and is particularly terse with any errors. It does not use the 32 bit version of prototyping and it does not check argument types or argument counts. On the bright side it frees you from endless prototyping which improves your coding speed once you are used to it.

The 64 bit version has its own libraries, include files, macro file and main header file "masm64rt.inc" and you must use them all together as they are written to work with each other.

This is how simple it is to create a console app. It is a standard template in the 64 bit version.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include64\masm64rt.inc

    .code

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

entry_point proc

    USING r12

    SaveRegs

    conout "Howdy, your new console template here.",lf,lf

    waitkey
    RestoreRegs
    .exit

entry_point endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    end

TimoVJL

remove these unnessary lines; *************************************************************************
; MASM32 proto types for Win32 functions and structures
; *************************************************************************
;include c:\masm32\include\kernel32.inc
;include c:\masm32\include\masm32.inc

; *************************************************************************
; MASM32 object libraries
; *************************************************************************
includelib c:\masm32\lib\masm32.lib
includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib
includelib Kernel32.lib

extern MessageBoxA: proc
extern CreateThread: proc
make input buffer larger.data?
array db BUF_LEN dup(?)
and put at endend
May the source be with you

aw27

#6
This is an example of mixing C++ and MASM, reusing as much as possible what this user dropped here.

C++ :


#include "stdio.h"
#include "conio.h"

extern "C"
{
void getCmdLineInput();
char helloMsg[];
}

int main()
{
printf("%s\n",helloMsg);
getCmdLineInput();
printf("Done! Press any key to exit.\n");
_getch();
return 0;
}


MASM:

STD_INPUT_HANDLE equ -10
STD_OUTPUT_HANDLE equ -11
BUF_LEN equ 80h
HANDLE typedef PTR VOID

extern GetStdHandle: proc
extern ReadFile: proc
extern CloseHandle : proc
extern WriteFile : proc

PrintString proto string : PTR, _size : DWORD, writeLenPtr : PTR

.data
helloMsg db "Hello, Tom, from VS2017 MASM64",0

.data?
BytesWritten dword ?
BytesRead dword ?
hFileRead HANDLE ?
hFileWrite HANDLE ?
array db BUF_LEN dup(?)

public helloMsg

.code

getCmdLineInput proc
sub rsp, 28h
mov ecx, STD_INPUT_HANDLE
call GetStdHandle 
mov hFileRead, rax

mov rcx, hFileRead
lea rdx, array
mov r8d, BUF_LEN
lea r9, BytesRead
mov qword ptr [rsp+20h], 0
call ReadFile
cmp eax, 0
jz @exit
lea rcx, array
mov edx, BytesRead
lea r8, BytesWritten
call PrintString
@exit:
add rsp, 28h
ret
getCmdLineInput endp


PrintString proc string : PTR, _size : DWORD, writeLenPtr : PTR
sub rsp, 30h
mov string, rcx
mov _size, edx
mov writeLenPtr, r8

mov ecx, STD_OUTPUT_HANDLE
call GetStdHandle
mov hFileWrite, rax

mov rcx, hFileWrite
mov rdx, string
mov r8d, _size
mov r9, writeLenPtr
mov qword ptr [rsp+20h], 0
call WriteFile

ret
PrintString endp

end


Test Output:
Hello, Tom, from VS2017 MASM64
Visual Studio 2017 masm64 just refers to using masm 64bit with ML64.exe compiler
Visual Studio 2017 masm64 just refers to using masm 64bit with ML64.exe compiler
Done! Press any key to exit.


I attach the built .exe but don't attach the project file because everybody can do that  :t




BugCatcher

You need to study what macros are for. Study the masm tutorials that have macros declared in them.

TBRANSO1

Alright, thanks for the input, everyone.  I am still a learner.  I had read about macros in an assembly textbook, but it didn't give a lot of examples, so I wasn't really sure how to use them, just practicing.

I will work on getting the masm64 libraries installed.

I use Microsoft VS Code or VS Studio as the IDE for a lot of languages.  I use Python(VS Studio and PyCharm), Ruby(RubyCharm), Java (Eclispe), Elixir, Rust, C, C++, and more.  I got a taste for assembly in school and enjoy it.  I am now in a graduate program. I had done simple stuff with assembly, either with Intel or ATT syntax, but am ready to conquer more complex stuff.  Sometimes, when coding in OOP languages, my head gets cloudy with all the indirection and abstraction.  I use assembly as a centering force, since it's more on the metal... I think that it provides a nice distraction and more visual, direct presentation of code. I get excited to move stuff around registers and when it works, more excited.

I guess that this begs the question: what are your opinions on OOP languages?  Personally, I enjoy them, but find them frustrating sometimes when trying to read across what seems 100 different indirection calls trying to track down stuff.  Stuff is buried in stuff.. and sometimes I think to myself, that some of the code could have simply been solved with a few lines of C or assembly???

Anyways, I am just trying to prepare the IDE programming environment for more serious stuff.


TBRANSO1

Quote from: AW on November 30, 2018, 08:42:36 PM
Test Output:
Hello, Tom, from VS2017 MASM64
Visual Studio 2017 masm64 just refers to using masm 64bit with ML64.exe compiler
Visual Studio 2017 masm64 just refers to using masm 64bit with ML64.exe compiler
Done! Press any key to exit.


I attach the built .exe but don't attach the project file because everybody can do that  :t

@AW

I see that you removed what I thought was a required stack alignment.  I am still learning, I read on MSDN that it was required at the entry for 64 bit, and found that bit of code of "mov spl, -16" on OS.  I don't know the difference.  https://docs.microsoft.com/en-us/cpp/build/alloca?view=vs-2017. I guess that I am clueless on when and how to use this part?

Thank you, AW

aw27

#10
I didn't skip the stack alignment requirement. I know it is aligned so don't need to do anything else. In cases where we use a few local variables we may be a bit lost in the end how the alignment will be after that, so doing and rsp, -16 makes a blind alignment.
Don't excuse yourself invoking that your talent is for other programming flavours. You are disorganized and without clear concepts, this will surface in any other programming variation.

PS: In spite of my speech  :badgrin: there was a stack misalignment in my code, which I fixed.
I have also done some optimizations to reduce the file size to only 3072 bytes.

felipe

What i think of java is: "If you need a virtual machine to program, you better buy a toy pc and stay away from real hardware..."  :lol:... :badgrin:

TBRANSO1

Quote from: AW on December 01, 2018, 01:53:21 PM
I didn't skip the stack alignment requirement. I know it is aligned so don't need to do anything else. In cases where we use a few local variables we may be a bit lost in the end how the alignment will be after that, so doing and rsp, -16 makes a blind alignment.
Don't excuse yourself invoking that your talent is for other programming flavours. You are disorganized and without clear concepts, this will surface in any other programming variation.

PS: In spite of my speech  :badgrin: there was a stack misalignment in my code, which I fixed.
I have also done some optimizations to reduce the file size to only 3072 bytes.

I made the previous adjustments, and I think there was one different thing, but it worked as expected.

I think that I see that you changed the 28h to 30h in the PrintString proc, was there anything else?

I think that this is what I need to understand better is proper stack alignment or procedures, how much to subtract entering any function.  I also have some difficulty determining where parameters are relative to the base and stack pointer.  It's kind of hunt and peck right now... kind of like, let's see if its 4 or 8 or 12 bytes above... oops, nope segmentation fault, then maybe it's below... lol. I'm sure it will get easier.  I need to actually draw a stack on paper and be more accurate in planning... things obviously that don't need to be done with using a higher level language.


I don't mind Java, C# and whatnot, it's kind of planned and canned though... just use a library and code the way Java or C# tells you.  C obviously has it's syntacical rules, but I like the closeness and sometimes the creativity to things.  Ruby or Python are so close, and Ruby is funny since it's sugary sweet with so much syntactic sugar.  Although looking at Ruby's metaprogramming could make you pull your hair out.  I think how many ways can you put lipstick on a for or while statement in the Enumeration class.  It has adopted so many techniques from other languages that I see Java, C#, C++, C, Python, Rust, Go, you name it in the language.  It's only an observation, I love the language as it was my first love. Ha ha.




aw27

Quote
I think that I see that you changed the 28h to 30h in the PrintString proc, was there anything else?

This is very easy and at the same time very difficult to internalize (some people take years and most never do). This is the reason you find people saying that x64 is not worthwhile when the true reason is that they are not able to internalize the stack alignment.
There are 2 parts to consider, the x64 Windows ABI part and the MASM part. I assume you already know the x64 ABI part.
The MASM part is easy as well:
1) If the assembler sees a function without parameters and/or local variables it assumes (wrongly or not) it is a leaf function and will not build an rbp based frame. In this case, if you subtract a value to the stack pointer in the prologue you must add it in the epilogue, otherwise the function will crash.
2) If the assembler sees a function with parameters and/or local variables, it has a default prologue and epilogue for it.
This is the case of our PrintString function. In this case it automatically makes an rbp based frame, which happens to align the stack to 16 bytes, since it makes a push. The default epilogue uses the leave instruction before ret, so we don't need to bother about restoring the stack with add rsp, xxx.
And this is all you need to know.
Of course, I did sub rsp, 30h in PrintString because WriteFile has 5 parameters, otherwise (with 4 or less) sub rsp, 20h would be enough to keep the alignment.


hutch--

Having read these posts, now you know why I wrote matching prologues and epilogues so that you are free of the guesswork to balance the stack. ML64 is by no means a friendly tool but if you get it right, there is little that you cannot do.