Author Topic: Help with Hello World and NASM on mingw64  (Read 12669 times)

Offline smaudet

  • Jr. Member
  • *
  • Posts: 4
Help with Hello World and NASM on mingw64
« on: November 25, 2018, 12:47:00 AM »
Hello all.

So I was trying to learn the NASM assembler a bit more, my end goal is to be able to try to load some library and be able to call it with arbitrary arguments, in particular problably kernel32.dll (I don't know if its even possible yet)...

Anyways, I'm faced with a much more immediate problem, I can't get Hello World to work on windows with the nasm compiler and the gcc linker. I'm using MSYS2's variant of MINGW64, and I've the following code:

; ----------------------------------------------------------------------------
; helloworld.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It needs to be linked with a C library.
; ----------------------------------------------------------------------------

; https://forum.nasm.us/index.php?topic=810.0 ???

global  main
extern  printf

section .text

main:
    push    message
    call    printf
    ; add     esp, 4
    ; call    ExitProcess
    ret
message:
    db  'Hello, World', 10, 0

I'm using the following:

nasm -f win64 -o win-nasm.obj win-nasm.asm
gcc -o win-nasm.exe win-nasm.obj

This produces a win-nasm.exe which promptly proceeds to segfault as soon as I attempt to run it.

I can get a Hello World to work from nasm but it has to be linked with golink (and it uses kernel32 directly) and it needs to be run from a command prompt. Does anyone know what I'm missing here?

Offline dreamCoder

  • Full Member
  • **
  • Posts: 107
Re: Help with Hello World and NASM on mingw64
« Reply #1 on: November 25, 2018, 12:56:18 PM »
1) You're compiling 32-bit source with NASM's "win64" switch
2) You're linking without being explicit of either "-m32" or "-m64" switch, according to #1.
3) You're linking to multiple libraries... "printf" belongs to GCC by default... "ExitProcess" belongs to "kernel32.dll". "printf" could also belong to "msvcrt.dll". Which one?
4) For GCC32 bit, you should know a thing or two about C calling convention and C general structure. 

Here's a recent example... closest to what you are asking
https://forum.nasm.us/index.php?topic=2475.0

Offline smaudet

  • Jr. Member
  • *
  • Posts: 4
Re: Help with Hello World and NASM on mingw64
« Reply #2 on: November 25, 2018, 11:08:57 PM »
1) What is 32 bit about it? the only explicitly 32 bit thing I see is the line that's commented out.
2) 32 bit won't even link. I verified -fwin64 means 64 bit code, not 32 (I know windows has this weird WOWSYS64 thing which is 32 bit, I don't think that's relevant here). -m64 corresponds to -fwin64, -m32 to -fwin32
3) I'm not using ExitProcess. Its commented out...I have a ret and I did also try with push 0. I'm not sure where/what printf is, nor how to specify that.
4) Link? I don't think I'm doing anything special here, I'm putting a string pointer on the stack and then invoking the C ABI?

That recent example is only dealing with the kernel calls and MSVC.... I'm specifically trying to figure out why mingw64 won't compile.

Worth saying the 64 bit stuff compiles and segfaults, the 32 bit stuff seems to get very confused.


Offline dreamCoder

  • Full Member
  • **
  • Posts: 107
Re: Help with Hello World and NASM on mingw64
« Reply #3 on: November 26, 2018, 06:40:17 AM »
It's a 32-bit code.

push message
call printf
add esp,4

is a 32-bit CDECL or C calling convention. For 64-bit code, it is different entirely. Using "push" indicates it is a 32-bit code. And should not be compiled with "-f win64" switch. And for that, choosing the right linking switches is crucial.
Code: [Select]
        extern printf
        extern scanf

        section .data
prmpt1: db 'Enter an integer: ',0
prmpt2: db 'Your integer is %lld',0ah,0
format: db '%lld',0
value:  dq 0

        section .text
global main
main:
        sub     rsp,40          ;stack alignment + shadow space

        mov     rcx,prmpt1
        call    printf

        mov     rdx,value
        mov     rcx,format
        call    scanf

        mov     rdx,qword[value]
        mov     rcx,prmpt2
        call    printf

        add     rsp,40
        ret

; nasm -f win64 myprog.asm
; gcc -m64 myprog.obj -s -o myprog.exe

At this point, I am not sure what exactly you want. The whole picture you're trying to give me is that you're using 32-bit code and 32-bit calling convention, compiled into 64-bit binary format (which is PE32+ instead of PE), using 32-bit linking switch.. Is that what you're trying to do? You need to make up your mind. 

EDIT: Added full 64-bit code and put them in a code tag
« Last Edit: November 26, 2018, 07:39:23 AM by dreamCoder »

Offline dreamCoder

  • Full Member
  • **
  • Posts: 107
Re: Help with Hello World and NASM on mingw64
« Reply #4 on: November 26, 2018, 06:59:37 AM »
Just in case you actually need to compile a 32-bit code, use this
Code: [Select]
        extern _printf
        extern _scanf

        section .data
prmpt1: db 'Enter an integer: ',0
prmpt2: db 'Your integer is %d',0ah,0
format: db '%d',0
value:  dd 0

        section .text
        global _WinMain@16

_WinMain@16:
        push    ebp
        mov     ebp,esp

        push    prmpt1
        call    _printf
        add     esp,4*1

        push    value
        push    format
        call    _scanf
        add     esp,4*2

        push    dword[value]
        push    prmpt2
        call    _printf
        add     esp,4*2

        mov     esp,ebp
        pop     ebp
        ret

; nasm -f win myprog.asm
; gcc -m32 myprog.obj -s -o myprog.exe

Calling convention makes a huge difference in the way you compile and link your code.

EDIT: I gave you a full 32-bit example and put them in a code tag.
« Last Edit: November 26, 2018, 07:27:57 AM by dreamCoder »

Offline smaudet

  • Jr. Member
  • *
  • Posts: 4
Re: Help with Hello World and NASM on mingw64
« Reply #5 on: November 26, 2018, 11:30:15 AM »
Thanks for the clarification.

Code: [Select]
; ----------------------------------------------------------------------------
; win-nasm-64.asm
;
; This is a Win64 console program that writes "Hello, World" on one line and
; then exits.  It needs to be linked with a C library.
; nasm -o win-nasm-64.obj -fwin64 win-nasm-64.asm && gcc -m64 win-nasm-64.obj -o win-nasm-64.exe
; ----------------------------------------------------------------------------

global  main
extern  printf

section .text

main:
    sub     rsp, 40
    mov     rcx, message
    call    printf
    add     rsp, 40
    ret
message:
    db  'Hello, World', 0

Is what I currently have.

In addition to your code, these were quite helpful to understand a bit better:
https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx

Regarding 'making up my mind', no, I'm just learning, hence I was just trying some simple examples and trying to establish a baseline. Good thing too, it seems it turned out the 'baseline' was much more involved than I had expected.

I seem to have 'conquered' the 64 bit example, now to try for 32 bit variants, proper makefiles, etc. :)

Thanks for your help!

Offline dreamCoder

  • Full Member
  • **
  • Posts: 107
Re: Help with Hello World and NASM on mingw64
« Reply #6 on: November 26, 2018, 01:10:40 PM »
Glad you sorted it out.

But be careful with what you read from MSDN. Some things don't quite apply to C when it comes to parameter-passing. For example, printf don't take in XMM arguments. So when it comes to C, I don't usually direct people to MS links and articles because they tend to mislead. Here, try this

format: db '%f',0
myFloat: dq 56.4067

movq xmm1,[myFloat]   ;according to "parameter-passing", myFloat should go here... but...
;mov rdx,[myFloat]
mov rcx,format
call printf

Good luck with your "64-bit conquest"  ;D 

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Help with Hello World and NASM on mingw64
« Reply #7 on: November 26, 2018, 08:12:24 PM »
Unless I'm mistaken (quite possible!) printf wants the count of float parameters in al.

Best,
Frank


Offline dreamCoder

  • Full Member
  • **
  • Posts: 107
Re: Help with Hello World and NASM on mingw64
« Reply #8 on: November 26, 2018, 08:42:31 PM »
Not on Win64 frank. For Linux64, yes. Things deviate sharply for C on both platforms.


Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Help with Hello World and NASM on mingw64
« Reply #9 on: November 26, 2018, 09:15:08 PM »
Okay, my mistake. Thanks dreamCoder!

Best,
Frank



Offline fredericopissarra

  • Full Member
  • **
  • Posts: 368
  • Country: br
Re: Help with Hello World and NASM on mingw64
« Reply #10 on: January 02, 2023, 01:03:04 PM »
Just in case you actually need to compile a 32-bit code, use this
Code: [Select]
...
_WinMain@16:
        push    ebp
        mov     ebp,esp
        ...
        mov     esp,ebp
        pop     ebp
        ret

Just 2 comments: Assuming MinGW32 is being used, the prolog/epilog isn't necessary... And WinMain@16 isn't necessary as well:
Code: [Select]
; test.asm
;
;   nasm -fwin32 -o test.o test.asm
;   gcc -o test.exe test.o
;
  bits  32

  extern _printf
  extern _scanf

  section .rodata

prmpt1: db 'Enter an integer: ',0
prmpt2: db `Your integer is %d\n`,0
format: db '%d',0

  section .bss

value:  resd 1

  section .text

  global _main

_main:
        push    prmpt1
        call    _printf
        add     esp,4*1

        push    value
        push    format
        call    _scanf
        add     esp,4*2

        push    dword [value]
        push    prmpt2
        call    _printf
        add     esp,4*2

        ret

Offline alCoPaUL

  • Jr. Member
  • *
  • Posts: 68
  • Country: ph
    • Webpage
Re: Help with Hello World and NASM on mingw64
« Reply #11 on: January 05, 2023, 08:19:13 PM »
just commenting on ret to exit after "call printf"...

i observed that you can get away with calling printf and then do ret and also you beginning your (64-bit) code with sub sp,8.

in windows 10 and 11, codes with features that i mentioned will exit normally if executed on console.

in windows 7 with all the updates, the code will execute, display what it needs to display but the console will raise an error.

So it's still stuck and being true with the description of assembly language being not portable.

bonus: if you disassemble a .net executable, you'll notice that the size of the stack is 8.

(im talking about codes that are assembled in NASM and Linked with Microsoft Linker to natively run on Windows subsystem)
« Last Edit: January 05, 2023, 08:23:56 PM by alCoPaUL »

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 368
  • Country: br
Re: Help with Hello World and NASM on mingw64
« Reply #12 on: January 05, 2023, 09:46:36 PM »
Why do you insist on using libc in a simple assembly program?
Yes... for Windows Console you'll need to use Win32 API, but you don't need libc (or msvcrt.dll):
Here's a simple Console program using ANSI codes for x86-64:
Code: [Select]
; test.asm
;
; nasm -fwin64 -o test.o test.asm
; x86_64-w64-mingw32-ld -s -o test.exe test.o -lkernel32
;
  bits  64
  default rel

  %define ENABLE_VIRTUAL_TERMINAL_PROCESSING 4
  %define STDOUT_HANDLE -11

  section .bss

mode:
  resd  1

  section .rodata

msg:
  db    `\033[1;31mH\033[1;32me\033[1;33ml\033[1;34ml\033[1;35mo\033[m\n`
msg_len equ $ - msg

  section .text

  ; Importadas de kernel32.dll
  extern __imp_GetStdHandle
  extern __imp_GetConsoleMode
  extern __imp_SetConsoleMode
  extern __imp_WriteConsoleA
  extern __imp_ExitProcess

  global _start

_start:
  mov   ecx,STDOUT_HANDLE
  call  [__imp_GetStdHandle]

  mov   rbx,rax                 ; Guarda handle.

  ; Habilita VT100 no Windows Terminal.
  mov   rcx,rax
  lea   rdx,[mode]
  call  [__imp_GetConsoleMode]
  mov   edx,[mode]
  or    edx,ENABLE_VIRTUAL_TERMINAL_PROCESSING
  mov   rcx,rbx
  call  [__imp_SetConsoleMode]

  mov   rcx,rbx
  lea   rdx,[msg]
  mov   r8d,msg_len
  xor   r9d,r9d
  push  0
  call  [__imp_WriteConsoleA]

  xor   ecx,ecx
  jmp  [__imp_ExitProcess]
And here is the same code, but for win32:
Code: [Select]
; test32.asm
;
; nasm -fwin32 -o test.o test.asm
; i686-w64-mingw32-ld -s -o test.exe test.o -lkernel32
;
  bits  32

  %define ENABLE_VIRTUAL_TERMINAL_PROCESSING 4
  %define STDOUT_HANDLE -11

  section .bss

mode:
  resd  1

  section .rodata

msg:
  db    `\033[1;31mH\033[1;32me\033[1;33ml\033[1;34ml\033[1;35mo\033[m\n`
msg_len equ $ - msg

  section .text

  ; Importadas de kernel32.dll
  extern __imp__GetStdHandle@4
  extern __imp__GetConsoleMode@8
  extern __imp__SetConsoleMode@8
  extern __imp__WriteConsoleA@20
  extern __imp__ExitProcess@4

  global _start

_start:
  push  STDOUT_HANDLE
  call  [__imp__GetStdHandle@4]

  mov   ebx,eax                 ; Store handle in ebx

  ; Habilita VT100 no Windows Terminal.
  push  mode
  push  eax
  call  [__imp__GetConsoleMode@8]

  mov   eax,[mode]
  or    eax,ENABLE_VIRTUAL_TERMINAL_PROCESSING
  push  eax
  push  ebx
  call  [__imp__SetConsoleMode@8]

  push  0
  push  0
  push  msg_len
  push  msg
  push  ebx
  call  [__imp__WriteConsoleA@20]

  push  0
  jmp   [__imp__ExitProcess@4]
No libc required.
« Last Edit: January 05, 2023, 09:55:35 PM by fredericopissarra »

Offline alCoPaUL

  • Jr. Member
  • *
  • Posts: 68
  • Country: ph
    • Webpage
Re: Help with Hello World and NASM on mingw64
« Reply #13 on: January 06, 2023, 05:12:29 PM »
^^

printf() works wonders with "%s".

say you wanna lazy convert a set of characters using xor and you wanna convert them back again but the "distance" of say "-" to "_" will produce non-displayable characters when converting them back or sometimes displaying unwanted spaces and such, just pass them to "%s" and it will be in pure text.. it's like the clean up process for text conversion..

also print() is the first ever c routine that was used to hello world everyone done by brian kernighan..

you just push the text and push to "%s" and then call printf().


Offline fredericopissarra

  • Full Member
  • **
  • Posts: 368
  • Country: br
Re: Help with Hello World and NASM on mingw64
« Reply #14 on: January 06, 2023, 07:36:17 PM »
Here's my opinion... this is NOT assembly... this is C, disguised as assembly...
Let's look at both codes:
Code: [Select]
/* test.c */
int main(void){puts("Hello");return0;}
Code: [Select]
; test64.asm
  bits 64
  default rel

  section .text

  extern puts

  global main
  align 4
main:
  sub rsp,8    ; aligning the stack, as per SysV ABI.
  lea  rdi,[hello]
  call  puts wrt ..plt
  add rsp,8
  ret

  section .rodata

msg:
  db 'Hello',0
Now compile both:
Code: [Select]
$ gcc -O2 -s -o test test.c
$ nasm -felf64 -o test64.o test64.asm
$ gcc -s -o test64 test64.o
$ ls -go test*
-rwxr-xr-x 1 14416 jan  6 16:23 test
-rwxr-xr-x 1 14416 jan  6 16:23 test64
-rw-r--r-- 1   201 jan  6 16:23 test64.asm
-rw-r--r-- 1   880 jan  6 16:23 test64.o
-rw-r--r-- 1    59 jan  6 16:28 test.c
There's NO difference!
This:
Code: [Select]
; test64-2.asm
  bits  64
  default rel

  section .text

  global _start
  align 4
_start:
  mov   eax,1
  mov   edi,eax
  lea   rsi,[hello]
  mov   edx,hello_len
  syscall

  mov   eax,60
  xor   eax,eax
  syscall

  section .rodata

hello:
  db  `Hello\n`
hello_len equ $ - hello
Code: [Select]
$ nasm -felf64 -o test64-2.o test64-2.asm
$ ld -s -o test64-2 test64-2.o
$  ls -go test64-2*
-rwxr-xr-x 1 8480 jan  6 16:31 test64-2
-rw-r--r-- 1  268 jan  6 16:30 test64-2.asm
-rw-r--r-- 1  880 jan  6 16:31 test64-2.o
Give you a image file almost 6 KiB smaller because all that code on c0.o (C Runtime) aren't being linked to your code.
« Last Edit: January 06, 2023, 08:01:02 PM by fredericopissarra »