flat assembler
Message board for the users of flat assembler.

Index > Windows > keep console

Author
Thread Post new topic Reply to topic
Jordi



Joined: 12 Dec 2012
Posts: 8
Jordi 12 Dec 2012, 10:20
Hello,

I searched the forum en the internet but the examples could not unfortunattly help me. All the examples look a little like my code except that I use stdcall and others not.

My goal is to startup the console, and keep it untill I enter a character.

Code:
format PE
entry start

include 'win32a.inc'
include 'api\kernel32.inc'


inputHandle dd ?
title db 'Derp derp',0
inputBuffer rb 256
hasRead dd 0
mustRead dd 0

start:
        stdcall [AllocConsole]
        stdcall [GetStdHandle], STD_INPUT_HANDLE
        mov [inputHandle], eax


        stdcall [ReadConsoleA], inputHandle, inputBuffer, mustRead, hasRead, NULL
        stdcall [ExitProcess], 0



data import
 library kernel,'KERNEL32.DLL'

 import kernel,\
        AllocConsole, 'AllocConsole',\
        ExitProcess, 'ExitProcess',\
        GetStdHandle, 'GetStdHandle',\
        SetConsoleTitleA, 'SetConsoleTitleA',\
        ReadConsoleA,'ReadConsoleA',\
        WriteConsoleA, 'WriteConsoleA'

end data                           


Could someone help me a little?
Post 12 Dec 2012, 10:20
View user's profile Send private message Reply with quote
gunblade



Joined: 19 Feb 2004
Posts: 209
gunblade 12 Dec 2012, 10:48
Code:
format PE Console
entry start

include 'win32a.inc'
include 'api\kernel32.inc'


inputHandle dd ?
title db 'Derp derp',0
inputBuffer rb 256
hasRead dd 0
mustRead dd 1

start:
        stdcall [GetStdHandle], STD_INPUT_HANDLE
        mov [inputHandle], eax


        stdcall [ReadConsoleA], [inputHandle], inputBuffer, [mustRead], hasRead, NULL
        stdcall [ExitProcess], 0

data import
 library kernel,'KERNEL32.DLL'

 import kernel,\
        ExitProcess, 'ExitProcess',\
        GetStdHandle, 'GetStdHandle',\
        SetConsoleTitleA, 'SetConsoleTitleA',\
        ReadConsoleA,'ReadConsoleA',\
        WriteConsoleA, 'WriteConsoleA'

end data    


No need for the AllocConsole if you use PE Console (I believe PE without any parameters defaults to PE Console anyway (correct me if i'm wrong here - but for me, it was opening a console anyway even without the console setting to the PE format)).

And yeah, 2 main issues - your mustRead was 0, should be at least 1. You were also passing the ADDRESS of inputHandle and mustRead, rather than the actual value - need to dereference those with the [] brackets.

Something which might be an issue - this will only exit once you enter the Enter key.. not ANY key. This is because the console and those console commands work per-line.. it will let you enter as many characters as you want, and only return from the ReadConsole when a newline is encountered.
Post 12 Dec 2012, 10:48
View user's profile Send private message Reply with quote
Jordi



Joined: 12 Dec 2012
Posts: 8
Jordi 12 Dec 2012, 15:13
Thank you for your response.

You where absolulty right.
First there is no need to allocate the console in PE mode.
And indeed I needed to dereference both the variables.

According to the reference both variables have the LP prefix. If I am correct this means that they are Long Pointers. Is that why I needed to dereference them? If so this makes a lot clear.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms684958(v=vs.85).aspx

Thank you for your help! Very Happy
Post 12 Dec 2012, 15:13
View user's profile Send private message Reply with quote
gunblade



Joined: 19 Feb 2004
Posts: 209
gunblade 12 Dec 2012, 15:25
Nah, its the other two variables..

inputHandle and mustRead are hConsoleInput and nNumberOfCharsRead respectively. These two are NOT lp*, and therefore these should be actual data/values. This is why you have to use [] brackets in order to pass the value at the address, rather than the address itself.

The other two parameters are lp*, and hence expect an address, where the function can then store the data (as these other parameters are OUT parameters). The function will write its output data to the address you give it.

In general, IN parameters tend to be data itself, whereas OUT will be addresses (as the function cannot directly modify the data that you pass it unless it knows where it is stored).

Slightly off-topic: you should use sections in your file, as in:

Code:
format PE Console
entry start

include 'win32a.inc'
include 'api\kernel32.inc'

section '.data' data readable writeable

inputHandle dd ?
title db 'Derp derp',0
inputBuffer rb 256
hasRead dd 0
mustRead dd 1

section '.text' code readable executable

start:
      stdcall [GetStdHandle], STD_INPUT_HANDLE
    mov [inputHandle], eax


      stdcall [ReadConsoleA], [inputHandle], inputBuffer, [mustRead], hasRead, NULL
       stdcall [ExitProcess], 0

section '.idata' import data readable

library kernel,'KERNEL32.DLL'

import kernel,\
      ExitProcess, 'ExitProcess',\
     GetStdHandle, 'GetStdHandle',\
   SetConsoleTitleA, 'SetConsoleTitleA',\
   ReadConsoleA,'ReadConsoleA',\
    WriteConsoleA, 'WriteConsoleA'    


It's good practice to have a section for data which is writeable, and a seperate section for the code which isnt. Otherwise some antiviruses (if not windows itself) might complain at code writing data to the executable section. (kind of impressed it actually worked with no section - i deffinetly thought windows would have forbidden it - but aparently not. It might if the No-Execute feature had been enabled).
Post 12 Dec 2012, 15:25
View user's profile Send private message Reply with quote
Jordi



Joined: 12 Dec 2012
Posts: 8
Jordi 12 Dec 2012, 16:49
I don't know if you have any C knowledge.

oke out parameters are like references in C. You pass the memory adress instead of the value.

like this
Code:
void doSomething(int& a_Par1)
{

}    


and to dereference like in C you use this. You pass the value...
Code:
(*itr)    
Post 12 Dec 2012, 16:49
View user's profile Send private message Reply with quote
gunblade



Joined: 19 Feb 2004
Posts: 209
gunblade 13 Dec 2012, 09:23
Yeah, you have it right in C - but C behaves differently by default.

Say you had an unsigned int value - if you were to call a function by doing something(value), you'd be by default passing the actual "data" inside that variable, rather than an address to it. If you wanted to explicitely pass the address to it, you'd have to do something(&value) as you say.

Whereas, in assembly, using the variable name actually uses the variable's address by default, so doing something like:

Code:
stdcall [something], value    


would actually be equivalent to the C of something(&value). You'd have to do:

Code:
stdcall [something], [value]    


to get the equivalent of something(value).

Although this also depends on the "type" used in C.. because for example, doing:

Code:
unsigned char buffer[256];    


will actually make the variable name buffer use the address by default (as its a reference to an array - you cant really pass the "value" as it could be of any length), so for that one - something(buffer) would be the equivalent of:

Code:
stdcall [something],buffer    


and something(*buffer) (which would be the same as something(buffer[0])) would by the equivalent of:

Code:
stdcall [something],[buffer]    



Hopefully that's not too unreadable Very Happy

There's a better explanation in section 1.2.3 of the fasm manual:
http://flatassembler.net/docs.php?article=manual#1.2.3
Post 13 Dec 2012, 09:23
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 13 Dec 2012, 10:54
Actually following lines are equivalent:
Code:
stdcall [something], args...
invoke  something, args...    
Moreover, stdcall [something], args... indeed is (*something)(args...); in C-speak: IAT (import address table that is made by import macro) consists of pointers to corresponding functions in kernel32.dll.
Post 13 Dec 2012, 10:54
View user's profile Send private message Reply with quote
gunblade



Joined: 19 Feb 2004
Posts: 209
gunblade 13 Dec 2012, 11:31
Yeah, I stuck to stdcall convension as it was what he used in his original code. Didnt want to add more confusion by switching it up Smile

But you're right, invoke is neater.. if you're already using macros, might as well use the neater of the two.
Post 13 Dec 2012, 11:31
View user's profile Send private message Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1396
Location: Piraeus, Greece
Picnic 13 Dec 2012, 11:58
Jordi wrote:
My goal is to startup the console, and keep it untill I enter a character.


Hi Jordi,

Idea You may also use getch from msvcrt library.
Below a script you might find helpful, notice the use of cinvoke here.

Code:
;#include <stdio.h>
;#include <conio.h>
;
;void main(void)
;{
;    int ch, scan;
;
;    do {
;        ch = getch();    /* 1st getch() gets ASCII code */
;        printf("Character is %d\n", ch);
;           if (ch == 0x00 || ch == 0XE0)  { /* if extended key */
;            scan = getch();  /* 2nd getch() gets "scan code" */
;            printf("\tExtended character:  scan is %d\n", scan);
;        }
;    }  while (ch != 27);    /* exit loop on ESC */
;}

    format pe console
    entry main

    include "win32ax.inc"

section ".data" data readable writeable

    CR equ 13,10
    chr dd 0
    scan dd 0

section ".code" code readable executable
main:

    .repeat
        cinvoke getch
        mov [chr], eax
        cinvoke printf, <"Character is %d",CR>, [chr]
        .if ( [chr] = 0x00 | [chr] = 0xE0 )
            cinvoke getch
            mov [scan], eax
            cinvoke printf, <0x09,"Extended character:  scan is %d",CR>, [scan]
        .endif
    .until ( [chr] = 27 )

    invoke ExitProcess, 0


section ".idata" import data readable writeable

    library kernel32,"KERNEL32.DLL",\
        msvcrt, "MSVCRT.DLL"

    include "include/api/kernel32.inc"

    import msvcrt,\
        getch, "_getch",\
        printf, "printf"    
    
Post 13 Dec 2012, 11:58
View user's profile Send private message Visit poster's website Reply with quote
Jordi



Joined: 12 Dec 2012
Posts: 8
Jordi 13 Dec 2012, 12:13
Thank you very much. This makes a lot clear. It is somethimes diffcult to do things that look quite simple in C or C++. Xd
Post 13 Dec 2012, 12:13
View user's profile Send private message Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2909
Location: 0x77760000
typedef 13 Dec 2012, 14:39
Jordi wrote:

like this
Code:
void doSomething(int& a_Par1)
{

}    



This is C++ not C. Very Happy
Post 13 Dec 2012, 14:39
View user's profile Send private message Reply with quote
Jordi



Joined: 12 Dec 2012
Posts: 8
Jordi 14 Dec 2012, 12:21
Hi i have got two more questions that are a little bit difficult to tackle.

First if I would like to print a double precision floating point it is quite easy

but if i would like to print a double precision floating point it seems really difficult. According to the documentation you could push a single precision floating point on the stack using

Code:
push dword 12.21
    


But when i print it it does show some weird output

Code:
format PE  Console
entry main
;include basic 32-bit code

include 'win32a.inc'
include 'api\kernel32.inc'

;define nessesary variable
section '.data' data readable writeable

inputHandle     dd      ?
title   db      'derp derp',0
inputBuffer     rb      256
hasRead dd      0
mustRead        dd      1
integerFormat   db      '%d',0
floatFormat     db      '%2.2f',0



section '.text' code readable executable

main:
        stdcall [GetStdHandle], STD_INPUT_HANDLE
        mov [inputHandle], eax

        push dword 12.12


        stdcall [printf], floatFormat, dword [esp]


       ; stdcall [printf], integerFormat, [var5]
        stdcall [ReadConsoleA], [inputHandle], inputBuffer, [mustRead], hasRead, NULL
        stdcall [ExitProcess], 0

section '.idata' import data readable writeable

        library kernel,'KERNEL32.DLL',\
                msvcrt,'msvcrt.dll'

        import kernel,\
               ExitProcess, 'ExitProcess',\
               GetStdHandle, 'GetStdHandle',\
               SetConsoleTitleA, 'SetConsoleTitleA',\
               ReadConsoleA,'ReadConsoleA'

        import msvcrt,\
               printf,'printf'
    


and my second question i also could find no answer on it nor on the forum, nor in the documentation. You could push memory, register or imediate value on the stack.

If i chouse the latter. How do i pop it from the stack. You could only pop memory and registers from the stack...

Could someone explain me this? Thank you very much. Very Happy
Post 14 Dec 2012, 12:21
View user's profile Send private message Reply with quote
Jordi



Joined: 12 Dec 2012
Posts: 8
Jordi 14 Dec 2012, 12:49
I found a answer on the last question.

If i push a 4 byte value on to the stack i could pop it of the stack to use pop with an operand. It does not mean that i must just that operand further.

However I still could not understand why I still could not print a signle precision floating point. Could someone help me with that?
Post 14 Dec 2012, 12:49
View user's profile Send private message Reply with quote
Jordi



Joined: 12 Dec 2012
Posts: 8
Jordi 14 Dec 2012, 14:31
Very Happy oew I suceeded. Shocked

What I did was that i converted the dword to a qword float so i was able to print it with printf.
Post 14 Dec 2012, 14:31
View user's profile Send private message Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2909
Location: 0x77760000
typedef 14 Dec 2012, 15:09
Your call to printf is wrong.
Code:
push dword 12.12 
stdcall [printf], floatFormat, dword [esp]
    


use this
Code:
 push dword 12.12
 push floatFormat
 call [printf]
 add esp, 8

; OR
cinvoke printf, floatFormat, 12.12

    
Post 14 Dec 2012, 15:09
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1657
Location: Toronto, Canada
AsmGuru62 14 Dec 2012, 16:22
Or you can store the 8 bytes directly from FPU into stack:
Code:
push 12.34
fld dword [esp]
push eax
fstp qword [esp]
    

but the 12.34 being FLOAT first and then DOUBLE will lose some precision.
Post 14 Dec 2012, 16:22
View user's profile Send private message Send e-mail Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 15 Dec 2012, 09:01
AsmGuru62,

With all due respect, why does anyone need FPU (for a constant case) if Win32AX.Inc already have pushd macro?
Code:
        pushd   double 12.34
;       push    0x4028AE14
;       push    0x7AE147AE    
Infer the implications. Wink
Post 15 Dec 2012, 09:01
View user's profile Send private message Reply with quote
Jordi



Joined: 12 Dec 2012
Posts: 8
Jordi 22 Dec 2012, 14:01
Aha okidokie thank you for the help.

I was wondering when you create a function at the end jou need to use a ret instruction to restore the stack.

I've created a function and I call the ret function, that is what i supposed to do according to the manual. However when I call the ret instruction my console crashes. It pops up and than it dissapears.

Am I doing something wrong. Sorry for al those questions but I really would like to understand fasm.

here is my code.

Code:
format PE
entry start
;include basic 32-bit code

include 'win32ax.inc'

;define nessesary variable

inputHandle     dd      ?
title   db      'Derp derp',0
inputBuffer     rb      256
hasRead dd      0
mustRead        dd      1
integerFormat   db      '%d',0
floatFormat     db      '%2.2f',0

start:

        stdcall [GetStdHandle], STD_INPUT_HANDLE
        mov [inputHandle], eax

        call WProc

        proc WProc
            mov edx, 12
            ret
        endp


        stdcall [printf], integerFormat, edx

        stdcall [ReadConsoleA], [inputHandle], inputBuffer, [mustRead], hasRead, NULL
        stdcall [ExitProcess], 0

data import
        library kernel,'KERNEL32.DLL',\
        msvcrt,'msvcrt.dll'

        import kernel,\
        ExitProcess, 'ExitProcess',\
        GetStdHandle, 'GetStdHandle',\
        SetConsoleTitleA, 'SetConsoleTitleA',\
        ReadConsoleA,'ReadConsoleA'

        import msvcrt,\
        printf,'printf'
end data
    



Thanks in advance.
Post 22 Dec 2012, 14:01
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 22 Dec 2012, 15:11
Jordi,

You've placed WProc() inside main function, this is wrong. Actually code of WProc() is executed twice: once because of call WProc, again because after return from call code path lies along it. Second time ret from this function returns to OS.

Move it below stdcall [ExitProcess], 0 and everything'll be OK.
Post 22 Dec 2012, 15:11
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.