Author Topic: print on windows  (Read 14639 times)

Offline Duck

  • Jr. Member
  • *
  • Posts: 2
  • Country: cl
print on windows
« on: August 27, 2021, 04:40:57 AM »
i am new to nasm and i trying to print a number in windows but i can't  :(
i don't want to use constants or printf

Code: [Select]
global _main
    extern  _GetStdHandle@4
    extern  _WriteFile@20
    extern  _ExitProcess@4

    section .text
_main:
    ; DWORD  bytes;   
    mov     ebp, esp
    sub     esp, 4
    mov     DWORD [ebp-4], 10

    push    -11
    call    _GetStdHandle@4
    mov     ebx, eax   

    push    0
    push    DWORD [ebp-4]
    lea     eax, [ebp-8]
    push    eax
    push    (message_end - message)
    push    message
    push    ebx
    call    _WriteFile@20

    push    0
    call    _ExitProcess@4

    hlt
message:
    db      "%d", 10
message_end:

help me please...
please  :(
« Last Edit: August 27, 2021, 04:43:28 AM by Duck »

Offline debs3759

  • Global Moderator
  • Full Member
  • *****
  • Posts: 224
  • Country: gb
    • GPUZoo
Re: print on windows
« Reply #1 on: August 27, 2021, 07:00:57 AM »
I've never programmed for Windows, but don't you need to include a .inc file (equivalent to a C header file) so nasm or your linker know where the routines you are calling are located?
My graphics card database: www.gpuzoo.com

Offline Duck

  • Jr. Member
  • *
  • Posts: 2
  • Country: cl
Re: print on windows
« Reply #2 on: August 27, 2021, 07:56:31 AM »
but don't you need to include a .inc file

not that i know, the truth, the following code works without problems

Code: [Select]
global _main
    extern  _GetStdHandle@4
    extern  _WriteFile@20
    extern  _ExitProcess@4

    section .text
_main: 
    mov     ebp, esp
    sub     esp, 4

    push    -11
    call    _GetStdHandle@4
    mov     ebx, eax   

    push    0
    lea     eax, [ebp-4]
    push    eax
    push    (message_end - message)
    push    message
    push    ebx
    call    _WriteFile@20

    push    0
    call    _ExitProcess@4

    hlt
message:
    db      'Hello, World', 10
message_end:

but the problem is that there the "hello word" is declared globally, that is, it is constant, i need it to be reserved in memory at runtime, not as constant if not using mov DWORD [ebp-4], 10

it has been very difficult for me to get info for windows, i know that it is easier and better for linux, but i need it for windows.  :(

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 373
  • Country: br
Re: print on windows
« Reply #3 on: August 27, 2021, 03:37:32 PM »
Use console API (not WriteFile). hello_win.asm (Windows x64), hello_win32.asm (Windows x86).
« Last Edit: August 27, 2021, 03:52:33 PM by fredericopissarra »

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 373
  • Country: br
Re: print on windows
« Reply #4 on: August 27, 2021, 04:06:14 PM »
If you need to print a string you'll need to pass the size of this string or, at least, use C style strings and put a NULL char at the and to get this size:

Code: [Select]
; Entry RDI - pointer to char
; Exit: EAX, size of string
; Destroys RDI.
strlen_:
  xor  eax,eax
.loop:
  cmp  byte [rdi],0
  je   .exit
  inc  eax
  inc  rdi
  jmp  .loop
.exit:
  ret

; Entry ECX = stdout handle. RDX = pointer to string.
; Destroys RDI, R8 and R9.
printstr:
  sub  rsp,40  ; Win64 calling convetion reserves 32 bytes on stack (will reserve 8 bytes more)
 
  mov rdi,rdx
  call  strlen_
  mov r8d,eax
  mov r9,rsp
  push 0
  call  [__imp_WriteConsoleA]

  add  rsp,40
  ret

Usage:
Code: [Select]
section .data

msg: db 'hello', 0

section .text
...
  ; rcx must have the stdout handle
  lea rdx,[msg]
  call printstr
« Last Edit: August 27, 2021, 04:10:12 PM by fredericopissarra »

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 373
  • Country: br
Re: print on windows
« Reply #5 on: August 27, 2021, 04:32:41 PM »
Now... if you want to allocate memory use VirtualAlloc() and VirtualFree() Win API functions. They are well documented in MSDN. Tip, as you can see the name of the 'stub' library used to call this functions from kernel32.dll are prefixed and suffixed (in 32 bits mode only) differently, accordingly to the mode used: x86-64 use __imp_ prefix only and i386 mode use prefix __imp__ and sufixed with @N, where N is the number of bytes of the arguments, pushed to the stack.

So, to allocate 128 bytes of memory in i386 mode you must do:
Code: [Select]
; allocate 128 bytes
  push 0       ; NULL.
  push 128     ; sizeof of requested block.
  push 0x1000 ; MEM_COMMIT
  push 4   ; PAGE_READWRITE
  call [__imp__VirtualAlloc@16]
  ; EAX has the address of buffer allocated.

  mov [allocaddr],eax    ; save it.

  ; It is prudent to call VirtualLock here.
  push eax
  push 128 ; size
  call [__imp__VirtualLock@8]
  ...
; deallocate buffer
  push [allocaddr]
  push 128 ; size
  call [__imp__VirtualUnlock@8]

  push [allocaddr]
  push 0 ; size (must be 0 to release memory).
  push 0x8000 ; MEM_RELEASE
  call [__imp__VirtualFree@12]
« Last Edit: August 27, 2021, 04:36:49 PM by fredericopissarra »