Author Topic: Some questions about an Asm Hello world Windows Program ?  (Read 2215 times)

Offline sunshine33

  • Jr. Member
  • *
  • Posts: 21
Some questions about an Asm Hello world Windows Program ?
« on: September 21, 2017, 01:05:15 PM »
Last time i was trying to fix an escaping program that was exiting too fast , now i have a different question .

What are these lines of code  ? Where can i learn more about those ?

Quote
 
 extern  _ExitProcess@4
 extern  _GetStdHandle@4
 extern  _WriteConsoleA@20
 extern  _ReadConsoleA@20


Code: [Select]
%include "io.inc"

section .text
global CMAIN
CMAIN:
   
  ; ----------------------------------------------------------------------------
; hello.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It uses only plain Win32 system calls from kernel32.dll, so it
; is very instructive to study since it does not make use of a C library.
; Because system calls from kernel32.dll are used, you need to link with
; an import library.  You also have to specify the starting address yourself.
;
; Assembler: NASM
; OS: Any Win32-based OS
; Other libraries: Use gcc's import library libkernel32.a
; Assemble with "nasm -fwin32 hello.asm"
; Link with "ld -e go hello.obj -lkernel32"
; ----------------------------------------------------------------------------

        global  go
        extern  _ExitProcess@4
        extern  _GetStdHandle@4
        extern  _WriteConsoleA@20
        extern  _ReadConsoleA@20

        section .data
msg:    db      'Hello, World', 10
handle:         dd      0
read_handle dd 0
written:        db      0

        section .text
go:
        ; handle = GetStdHandle(-11)
        push    dword -11
        call    _GetStdHandle@4
        mov     [handle], eax

        push -10  ; stdin
        call _GetStdHandle@4
        mov [read_handle], eax

        ; WriteConsole(handle, &msg[0], 13, &written, 0)
        push    dword 0
        push    written
        push    dword 13
        push    msg
        push    dword [handle]
        call    _WriteConsoleA@20

        push eax
        mov eax, esp ; buffer for char?
        push 0
        push written ; reuse this?
        push 1 ; characters to read?
        push eax
        push dword [read_handle]
        call  _ReadConsoleA@20
        pop eax ; character read in al?

        ; ExitProcess(0)
        push    dword 0
        call    _ExitProcess@4
    xor eax, eax
    ret

Offline stressful

  • Full Member
  • **
  • Posts: 105
  • Country: 00
    • CPU2.0
Re: Some questions about an Asm Hello world Windows Program ?
« Reply #1 on: September 21, 2017, 04:55:08 PM »
I think they''re called function decorations in Win32 API world. Doesn't quite apply in Win64. Function decorations is part of the Microsoft calling conventions (_cdecl and _stdcall) requirement for the functions of their libraries. In many cases, it also depends on the linkers to re-interpret / re-define how the decorated functions should appear in a source. To make it short, that's the names used when they are exported. So you should use them as such.

For Win32 API (like kernel32, user32 etc), each functions are followed by the "@xx" where xx is the number of 4-byte arguments needed by such function, in decimal.  For example, "ExitProcess" requires one argument so you call it as _ExitProcess@4. If 4 arguments (4 pushes), then it 's "@16".

For MSVCRT.dll (32-bit), the symbol @xx is not needed because it is not really a Win32 API in some sense. It's a runtime library. So all you need when calling "printf" is to supply the underscore (_printf) without @xx symbol. But again, the linkers impose their own requirements on decorated symbols. Golink, for example, doesn't require the underscore when calling functions in MSVCRT but does require full decorated function names for the Win32 APIs.

Win64 APIs don't have such fussy and confusing requirements.









Offline stressful

  • Full Member
  • **
  • Posts: 105
  • Country: 00
    • CPU2.0
Re: Some questions about an Asm Hello world Windows Program ?
« Reply #2 on: September 21, 2017, 05:02:52 PM »
Well if you happen to use the decorated names a lot in your source, you can re-define them by using %define directive.

extern _ExitProcess@4
%define ExitProcess _ExitProcess@4

But still this doesn't change the rules imposed by the linkers or the APIs though. It's is just for your own convenience.


Offline sunshine33

  • Jr. Member
  • *
  • Posts: 21
Re: Some questions about an Asm Hello world Windows Program ?
« Reply #3 on: September 21, 2017, 05:57:38 PM »
Thanks for the detailed reply .

I think they''re called function decorations in Win32 API world. Doesn't quite apply in Win64. Function decorations is part of the Microsoft calling conventions (_cdecl and _stdcall) requirement for the functions of their libraries. In many cases, it also depends on the linkers to re-interpret / re-define how the decorated functions should appear in a source. To make it short, that's the names used when they are exported. So you should use them as such.

For Win32 API (like kernel32, user32 etc), each functions are followed by the "@xx" where xx is the number of 4-byte arguments needed by such function, in decimal.  For example, "ExitProcess" requires one argument so you call it as _ExitProcess@4. If 4 arguments (4 pushes), then it 's "@16".

For MSVCRT.dll (32-bit), the symbol @xx is not needed because it is not really a Win32 API in some sense. It's a runtime library. So all you need when calling "printf" is to supply the underscore (_printf) without @xx symbol. But again, the linkers impose their own requirements on decorated symbols. Golink, for example, doesn't require the underscore when calling functions in MSVCRT but does require full decorated function names for the Win32 APIs.

Win64 APIs don't have such fussy and confusing requirements.

Well if you happen to use the decorated names a lot in your source, you can re-define them by using %define directive.

extern _ExitProcess@4
%define ExitProcess _ExitProcess@4

But still this doesn't change the rules imposed by the linkers or the APIs though. It's is just for your own convenience.

First of all let me start with some basics .


http://forum.codecall.net/topic/54789-assembly-language-basics-in-context-with-windows-api/
http://mathimaaran.angelfire.com/helloworld_tutorial.htm

Quote
The Win32 API


The Windows API (Application Programming Interface) includes the vast collection of data types, constants, functions, and structures used to create applications for the Windows OS. Most of the API functions, including ExitProcess which we used above, are stored in 3 main DLLs:

KERNEL32.DLL - Low level kernel services
GDI32.DLL - Graphics Device Interface: drawing and printing
USER32.DLL - User Interface controls, windows and messaging services

If you use windows API functions in your program, your program has to "import" the functions from the DLLs. Import libraries (.lib files) contain information the linker needs to resolve calls to functions residing in DLLs, so the system can load the specified DLL and locate the exported functions needed when your code is executed. For example, to call the ExitProcess function which resides in kernel32.dll, you must link your code with the import library kernel32.lib. However, the library file is not the only thing you need. An include file (kernel32.inc) is also needed.


Include (.inc) files contain "prototypes" which define the attributes of all functions stored in the DLL of the same name. These can be automatically generated from the library files using the lib2inc utiliy. There is no easy way of generating a library file from a given DLL but luckily most API functions you will require are located in DLLs for which the MASM32 distribution has appropriate library files.
The official Win32 API documentation is written for C and C++ programmers and a typical API function is defined in the following format:

Quote
include kernel32.inc - tells MASM to process the file named (as if the contents were copied into the sourcecode here)
includelib kernel32.lib - tells linker which import libraries to link with (kernel32.lib in this case).

Code: [Select]
[FONT=Tahoma][SIZE=3]ReturnType FunctionName ( ParamType1 ParamName1, ParamType2 ParamName2,...);
[/SIZE][/FONT]

Code: [Select]
extern MessageBoxA
import MessageBoxA user32.dll
These lines are added to indicate the Assembler that MessageBoxA is an
external function found in the dll, user32.dll.
All windows API functions which need to be used in the program should be imported in the same fashion.




Code: [Select]
%include "io.inc"

section .text
global CMAIN
CMAIN:
   
  ; ----------------------------------------------------------------------------
; hello.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It uses only plain Win32 system calls from kernel32.dll, so it
; is very instructive to study since it does not make use of a C library.
; Because system calls from kernel32.dll are used, you need to link with
; an import library.  You also have to specify the starting address yourself.
;
; Assembler: NASM
; OS: Any Win32-based OS
; Other libraries: Use gcc's import library libkernel32.a
; Assemble with "nasm -fwin32 hello.asm"
; Link with "ld -e go hello.obj -lkernel32"
; ----------------------------------------------------------------------------

        global  go
        extern  _ExitProcess@4
        extern  _GetStdHandle@4
        extern  _WriteConsoleA@20
        extern  _ReadConsoleA@20

        section .data
msg:    db      'Hello, World', 10
handle:         dd      0
read_handle dd 0
written:        db      0

        section .text
go:
        ; handle = GetStdHandle(-11)
        push    dword -11
        call    _GetStdHandle@4
        mov     [handle], eax

        push -10  ; stdin
        call _GetStdHandle@4
        mov [read_handle], eax

        ; WriteConsole(handle, &msg[0], 13, &written, 0)
        push    dword 0
        push    written
        push    dword 13
        push    msg
        push    dword [handle]
        call    _WriteConsoleA@20

        push eax
        mov eax, esp ; buffer for char?
        push 0
        push written ; reuse this?
        push 1 ; characters to read?
        push eax
        push dword [read_handle]
        call  _ReadConsoleA@20
        pop eax ; character read in al?

        ; ExitProcess(0)
        push    dword 0
        call    _ExitProcess@4
    xor eax, eax
    ret


Not sure which part of this program includes the required DLL  ?


Offline stressful

  • Full Member
  • **
  • Posts: 105
  • Country: 00
    • CPU2.0
Re: Some questions about an Asm Hello world Windows Program ?
« Reply #4 on: September 21, 2017, 06:32:13 PM »
sunshine33, you're confusing NASM vs MASM. Different assemblers have different ways of handling imports and external functions.

Quote
Not sure which part of this program includes the required DLL  ?

Look up MSDN for the selected entry. At the bottom of that page, you'll find the library that a function belongs to (kernel32, user32, gdi msvcrt etc).
« Last Edit: September 21, 2017, 06:46:50 PM by stressful »

Offline sunshine33

  • Jr. Member
  • *
  • Posts: 21
Re: Some questions about an Asm Hello world Windows Program ?
« Reply #5 on: September 21, 2017, 06:39:56 PM »
stressful
Thanks a lot for all the help , i have learned a lot from this thread :-)

Offline stressful

  • Full Member
  • **
  • Posts: 105
  • Country: 00
    • CPU2.0
Re: Some questions about an Asm Hello world Windows Program ?
« Reply #6 on: September 21, 2017, 06:47:26 PM »
Code: [Select]
extern  _ExitProcess@4
 extern  _GetStdHandle@4
 extern  _WriteConsoleA@20
 extern  _ReadConsoleA@20

This is basically how we "import" functions from external libraries. The existence of such functions is resolved during linking, by using a linker, and not at compile time. An assembler simply doesn't care if such function exists or not, but they must be properly declared in your source prior to using them.

After a successful compilation, the assembler is no longer involved. The next phase is carried out by the linkers and you must observe the linking rules imposed by the linkers at this particular stage. If your binaries failed this linking stage, then it produces linking error.

Offline sunshine33

  • Jr. Member
  • *
  • Posts: 21
Re: Some questions about an Asm Hello world Windows Program ?
« Reply #7 on: September 21, 2017, 07:17:14 PM »
Code: [Select]
extern  _ExitProcess@4
 extern  _GetStdHandle@4
 extern  _WriteConsoleA@20
 extern  _ReadConsoleA@20

This is basically how we "import" functions from external libraries. The existence of such functions is resolved during linking, by using a linker, and not at compile time. An assembler simply doesn't care if such function exists or not, but they must be properly declared in your source prior to using them.

After a successful compilation, the assembler is no longer involved. The next phase is carried out by the linkers and you must observe the linking rules imposed by the linkers at this particular stage. If your binaries failed this linking stage, then it produces linking error.


So all i need to do is Assemble and Link the program manually like this

Quote
; Assemble with "nasm -fwin32 hello.asm"
; Link with "ld -e go hello.obj -lkernel32"

Code: [Select]
%include "io.inc"

section .text
global CMAIN
CMAIN:
   
  ; ----------------------------------------------------------------------------
; hello.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It uses only plain Win32 system calls from kernel32.dll, so it
; is very instructive to study since it does not make use of a C library.
; Because system calls from kernel32.dll are used, you need to link with
; an import library.  You also have to specify the starting address yourself.
;
; Assembler: NASM
; OS: Any Win32-based OS
; Other libraries: Use gcc's import library libkernel32.a
; Assemble with "nasm -fwin32 hello.asm"
; Link with "ld -e go hello.obj -lkernel32"
; ----------------------------------------------------------------------------

        global  go
        extern  _ExitProcess@4
        extern  _GetStdHandle@4
        extern  _WriteConsoleA@20
        extern  _ReadConsoleA@20

        section .data
msg:    db      'Hello, World', 10
handle:         dd      0
read_handle dd 0
written:        db      0

        section .text
go:
        ; handle = GetStdHandle(-11)
        push    dword -11
        call    _GetStdHandle@4
        mov     [handle], eax

        push -10  ; stdin
        call _GetStdHandle@4
        mov [read_handle], eax

        ; WriteConsole(handle, &msg[0], 13, &written, 0)
        push    dword 0
        push    written
        push    dword 13
        push    msg
        push    dword [handle]
        call    _WriteConsoleA@20

        push eax
        mov eax, esp ; buffer for char?
        push 0
        push written ; reuse this?
        push 1 ; characters to read?
        push eax
        push dword [read_handle]
        call  _ReadConsoleA@20
        pop eax ; character read in al?

        ; ExitProcess(0)
        push    dword 0
        call    _ExitProcess@4
    xor eax, eax
    ret




Instead of using the default options here in SASM IDE .





So that , it would use the external function found in the dll KERNEL32.DLL ?

Offline stressful

  • Full Member
  • **
  • Posts: 105
  • Country: 00
    • CPU2.0
Re: Some questions about an Asm Hello world Windows Program ?
« Reply #8 on: September 21, 2017, 08:00:03 PM »
sunshine33, I am not familiar with SASM. But it looks like you have many duplicates and mismatch in there.

Issues;

1. ld requires the entry point "start", "_start" or "Start". This is ld (linker's) requirement. You have 2 different entry points, CMAIN and go ... which are duplicates and non-ld friendly anyway. My guess is that SASM puts CMAIN there for you by default?

2. "io.inc" is not exposed. I don't have the slightest clues what it contains and what it does.

3. I don't know what "libkernel.a" is. Looks like SASM is pre-configuring it for you or SASM has its own set of kernel library?

My suggestion is that you avoid SASM at this moment because it has many configuration defaults that may be conflicting with others such as the linkers.

I modified your code so that it works with GCC as the linker. GCC is including the "kernel32.dll" by default. This runs from the console. There are small modifications as well;

Code: [Select]
;Compile: nasm -f win this.asm
;Link: gcc -m32 this.obj -s -o this.exe

        global _WinMain@16
        extern _ExitProcess@4
        extern _GetStdHandle@4
        extern _WriteConsoleA@20
        extern _ReadConsoleA@20


section .data
msg:    db 'Hello, World',0
handle: dd 0
read_handle dd 0
written dd 0    ;This should not be a byte.


section .text
_WinMain@16:
        ; handle = GetStdHandle(-11)
        push    dword -11
        call    _GetStdHandle@4
        mov     [handle], eax

        push    dword -10  ; stdin
        call    _GetStdHandle@4
        mov     [read_handle], eax

        ; WriteConsole(handle, &msg[0], 13, &written, 0)
        push    dword 0
        push    written
        push    dword 12
        push    msg
        push    dword [handle]
        call    _WriteConsoleA@20

        push    eax
        mov     eax, esp ; buffer for char?
        push    0
        push    written ; reuse this?
        push    dword 1 ; characters to read?
        push    eax
        push    dword [read_handle]
        call    _ReadConsoleA@20
        pop     eax ; character read in al?

        ; ExitProcess(0)
        push    dword 0
        call    _ExitProcess@4

p/s You probably need to upgrade your GCC from mingw to TDM-GCC and set the correct PATH to it.


« Last Edit: September 21, 2017, 08:04:36 PM by stressful »

Offline sunshine33

  • Jr. Member
  • *
  • Posts: 21
Re: Some questions about an Asm Hello world Windows Program ?
« Reply #9 on: September 21, 2017, 08:39:54 PM »
sunshine33, I am not familiar with SASM. But it looks like you have many duplicates and mismatch in there.

Issues;

1. ld requires the entry point "start", "_start" or "Start". This is ld (linker's) requirement. You have 2 different entry points, CMAIN and go ... which are duplicates and non-ld friendly anyway. My guess is that SASM puts CMAIN there for you by default?

2. "io.inc" is not exposed. I don't have the slightest clues what it contains and what it does.

3. I don't know what "libkernel.a" is. Looks like SASM is pre-configuring it for you or SASM has its own set of kernel library?

My suggestion is that you avoid SASM at this moment because it has many configuration defaults that may be conflicting with others such as the linkers.

I modified your code so that it works with GCC as the linker. GCC is including the "kernel32.dll" by default. This runs from the console. There are small modifications as well;

Code: [Select]
;Compile: nasm -f win this.asm
;Link: gcc -m32 this.obj -s -o this.exe

        global _WinMain@16
        extern _ExitProcess@4
        extern _GetStdHandle@4
        extern _WriteConsoleA@20
        extern _ReadConsoleA@20


section .data
msg:    db 'Hello, World',0
handle: dd 0
read_handle dd 0
written dd 0    ;This should not be a byte.


section .text
_WinMain@16:
        ; handle = GetStdHandle(-11)
        push    dword -11
        call    _GetStdHandle@4
        mov     [handle], eax

        push    dword -10  ; stdin
        call    _GetStdHandle@4
        mov     [read_handle], eax

        ; WriteConsole(handle, &msg[0], 13, &written, 0)
        push    dword 0
        push    written
        push    dword 12
        push    msg
        push    dword [handle]
        call    _WriteConsoleA@20

        push    eax
        mov     eax, esp ; buffer for char?
        push    0
        push    written ; reuse this?
        push    dword 1 ; characters to read?
        push    eax
        push    dword [read_handle]
        call    _ReadConsoleA@20
        pop     eax ; character read in al?

        ; ExitProcess(0)
        push    dword 0
        call    _ExitProcess@4

p/s You probably need to upgrade your GCC from mingw to TDM-GCC and set the correct PATH to it.

I have only installed SASM a week ago , i tried many IDE's but sort of liked SASM IDE because it looked very user friendly .

This is how the SASM default code opens up .







This is what is inside the %include "io.inc"

https://pastebin.com/raw/KBbnHLsb


Code: [Select]
[code]%include "io.inc"

section .text
global CMAIN
CMAIN:
   
  ; ----------------------------------------------------------------------------
; hello.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It uses only plain Win32 system calls from kernel32.dll, so it
; is very instructive to study since it does not make use of a C library.
; Because system calls from kernel32.dll are used, you need to link with
; an import library.  You also have to specify the starting address yourself.
;
; Assembler: NASM
; OS: Any Win32-based OS
; Other libraries: Use gcc's import library libkernel32.a
; Assemble with "nasm -fwin32 hello.asm"
; Link with "ld -e go hello.obj -lkernel32"
; ----------------------------------------------------------------------------

        global  go
        extern  _ExitProcess@4
        extern  _GetStdHandle@4
        extern  _WriteConsoleA@20
        extern  _ReadConsoleA@20

        section .data
msg:    db      'Hello, World', 10
handle:         dd      0
read_handle dd 0
written:        db      0

        section .text
go:
        ; handle = GetStdHandle(-11)
        push    dword -11
        call    _GetStdHandle@4
        mov     [handle], eax

        push -10  ; stdin
        call _GetStdHandle@4
        mov [read_handle], eax

        ; WriteConsole(handle, &msg[0], 13, &written, 0)
        push    dword 0
        push    written
        push    dword 13
        push    msg
        push    dword [handle]
        call    _WriteConsoleA@20

        push eax
        mov eax, esp ; buffer for char?
        push 0
        push written ; reuse this?
        push 1 ; characters to read?
        push eax
        push dword [read_handle]
        call  _ReadConsoleA@20
        pop eax ; character read in al?

        ; ExitProcess(0)
        push    dword 0
        call    _ExitProcess@4
    xor eax, eax
    ret

Quote
I modified your code so that it works with GCC as the linker. GCC is including the "kernel32.dll" by default. This runs from the console. There are small modifications as well;



Code: [Select]
;Compile: nasm -f win this.asm
;Link: gcc -m32 this.obj -s -o this.exe

        global _WinMain@16
        extern _ExitProcess@4
        extern _GetStdHandle@4
        extern _WriteConsoleA@20
        extern _ReadConsoleA@20


section .data
msg:    db 'Hello, World',0
handle: dd 0
read_handle dd 0
written dd 0    ;This should not be a byte.


section .text
_WinMain@16:
        ; handle = GetStdHandle(-11)
        push    dword -11
        call    _GetStdHandle@4
        mov     [handle], eax

        push    dword -10  ; stdin
        call    _GetStdHandle@4
        mov     [read_handle], eax

        ; WriteConsole(handle, &msg[0], 13, &written, 0)
        push    dword 0
        push    written
        push    dword 12
        push    msg
        push    dword [handle]
        call    _WriteConsoleA@20

        push    eax
        mov     eax, esp ; buffer for char?
        push    0
        push    written ; reuse this?
        push    dword 1 ; characters to read?
        push    eax
        push    dword [read_handle]
        call    _ReadConsoleA@20
        pop     eax ; character read in al?

        ; ExitProcess(0)
        push    dword 0
        call    _ExitProcess@4

This program works without any of those

Quote
%include "io.inc"
global CMAIN
CMAIN: