NASM - The Netwide Assembler

NASM Forum => Programming with NASM => Topic started by: smaudet on November 25, 2018, 12:47:00 AM

Title: Help with Hello World and NASM on mingw64
Post by: smaudet 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?
Title: Re: Help with Hello World and NASM on mingw64
Post by: dreamCoder 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
Title: Re: Help with Hello World and NASM on mingw64
Post by: smaudet 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.

Title: Re: Help with Hello World and NASM on mingw64
Post by: dreamCoder 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
Title: Re: Help with Hello World and NASM on mingw64
Post by: dreamCoder 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.
Title: Re: Help with Hello World and NASM on mingw64
Post by: smaudet 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!
Title: Re: Help with Hello World and NASM on mingw64
Post by: dreamCoder 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 
Title: Re: Help with Hello World and NASM on mingw64
Post by: Frank Kotler 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

Title: Re: Help with Hello World and NASM on mingw64
Post by: dreamCoder on November 26, 2018, 08:42:31 PM
Not on Win64 frank. For Linux64, yes. Things deviate sharply for C on both platforms.

Title: Re: Help with Hello World and NASM on mingw64
Post by: Frank Kotler on November 26, 2018, 09:15:08 PM
Okay, my mistake. Thanks dreamCoder!

Best,
Frank


Title: Re: Help with Hello World and NASM on mingw64
Post by: fredericopissarra 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
Title: Re: Help with Hello World and NASM on mingw64
Post by: alCoPaUL 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)
Title: Re: Help with Hello World and NASM on mingw64
Post by: fredericopissarra 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.
Title: Re: Help with Hello World and NASM on mingw64
Post by: alCoPaUL 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().

Title: Re: Help with Hello World and NASM on mingw64
Post by: fredericopissarra 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.
Title: Re: Help with Hello World and NASM on mingw64
Post by: alCoPaUL on January 06, 2023, 11:01:44 PM
^^ seems to be reversed in windows coz usually a portable win32(x64/x86_32) file is larger than any code that has functions that are dependent on outside libraries.

like you even need to install runtimes if you just wanna make your small program to execute a basic routine.

and yes, in some instances, a code could be smaller if it directly calls the built-in dlls like kernel32.dll or ntdll.dll.

but generally, for hlls, you need to install the language runtimes and if you want your code to run on a computer without the runtime, you have to make your code carry the runtime itself (or something like that)/
Title: Re: Help with Hello World and NASM on mingw64
Post by: alCoPaUL on January 06, 2023, 11:53:15 PM
so if you just want to deploy a code that is heavy on C runtime usage on a certain OS (Windows 10 for example), get the appropriate Visual Studio version that builds Windows 10 programs by default. you won't concern or concern less if your code will run on Windows 10 coz it will surely can.

or just call the equivalent native APIs to do the same thing as your runtime dependent code and likely your code will be backwards-compatible.
Title: Re: Help with Hello World and NASM on mingw64
Post by: fredericopissarra on January 07, 2023, 12:32:46 AM
You are not understanding what I've said.. "C Runtime" object file is the initialization file linked to EVERY executable (those extra 6 KiB). A lot of initialization is made for a C program to work and, since the "assembly" (in disguise) program uses libc functions, the initialization must be linked to your code...

There is also the MSVCRT.DLL and other files used by your code (take a look with ldd utility). In my exemple, after loaded, the program uses, let's say, 1 KiB of RAM, your C disguised as "assembly" program uses way more...

And I want to deploy a program with NO C runtime dependency and I do not use Visual Studio (argh!). On Windows platform the principle is the same: You can import Win32 API routines, which are independent from C Runtime. This will instruct the linker to load the DLLs using early binding. And will work on EVERY single one of Windows versions, since Windows NT or Windows 95 until Windows 11. No C Runtime needed.

And no... Pure assembly code will always be smaller than mixed asm & C Runtime initialization routines... For the same code, I mean...
Title: Re: Help with Hello World and NASM on mingw64
Post by: alCoPaUL on January 07, 2023, 01:07:30 AM
well i can speak for windows coz i delved on windows assembly doing a short personal project.

when you throw an assembly code (win32 or variants) to a disassembler (ida64), it doesn't break down the printf() to pieces, as you were implying.

you can step into the printf() but that's already the code referencing the function and going through it in the msvcrt.dll.

but i might be mistaken, tho. i don't do linux programming or any linux "virtual machine to windows" programming such as ming64 as you were using linux code to explain your side. the OP was using linux assembly so. :D
Title: Re: Help with Hello World and NASM on mingw64
Post by: fredericopissarra on January 07, 2023, 11:57:58 AM
well i can speak for windows coz i delved on windows assembly doing a short personal project.

when you throw an assembly code (win32 or variants) to a disassembler (ida64), it doesn't break down the printf() to pieces, as you were implying.

you can step into the printf() but that's already the code referencing the function and going through it in the msvcrt.dll.
Again.. I never said that... libc function are implemented somewhere, if not statically linked, then in a DLL (or shared object file). In the case of Windows, it is in MSVCRT.DLL or equivalent.

Use your debugger and see what your C disguised as assembly program do from the beginning (not main(), but the image entry point) and you'll see.

Quote
but i might be mistaken, tho. i don't do linux programming or any linux "virtual machine to windows" programming such as ming64 as you were using linux code to explain your side. the OP was using linux assembly so. :D
There's no difference. C Runtime code is still linked to yours, using MinGW, Cygwin or the crappy Visual Studio linker...

My point is: If you have to use C functions from libc, do your program in C. It'll generate better code than yours, probably.
Title: Re: Help with Hello World and NASM on mingw64
Post by: fredericopissarra on January 07, 2023, 12:21:54 PM
A simple example:
Code: [Select]
; test.asm
;    nasm -g -fwin64 -o test.o test.asm
;    x86_64-w64-mingw32-gcc -g -o test.exe test.o
;
  bits  64
  default rel

  section .rodata

str:
  db  'Hello',0

  section .text

  extern puts

  ; I hope this works, I don't have Windows here to test.
  global main
  align 4
main:
  xor  eax,eax
  push rax       ; Align RSP and save return value.
  lea   rcx,[str]
  call  puts

  pop rax
  ret
After compiling and linking, using x86_64-w64-mingw32-objdump to get the actual code created:
Code: [Select]
$ x86_64-w64-mingw32-objdump -dM intel test.exeSee the dump file linked.
PS: I've added stack alignment later, there is 3 instructions missing in the listing (but I hope you get the idea)

Title: Re: Help with Hello World and NASM on mingw64
Post by: debs3759 on January 07, 2023, 04:24:46 PM
As this is a NASM forum, I fail to see the point of posts arguing that C is better.

Given optimised code, and without using outside libraries, asm will always be smaller and/or faster. I know some C compilers will generate better optimisations than the average asm coder, but all being equal, asm is far superior, even if harder to gain competency in :)
Title: Re: Help with Hello World and NASM on mingw64
Post by: fredericopissarra on January 07, 2023, 08:06:22 PM
As this is a NASM forum, I fail to see the point of posts arguing that C is better.

Given optimised code, and without using outside libraries, asm will always be smaller and/or faster. I know some C compilers will generate better optimisations than the average asm coder, but all being equal, asm is far superior, even if harder to gain competency in :)
Could be smaller (without linking to the entire C Runtime initialization and finalization code), but surely, most of the time won't be faster. As you said, modern C compilers optimizes things an experienced assembly programmer ignores, most of the time. For example: GCC considers minimizing branch prediction and cache misses penalties and improving instruction scheduling -- which is difficult to do by hand. Granted, sometimes the high level language do something redundant (or it seems to be), but, again, most of the time, the generate code is hard to beat, in terms of performance.

Btw, using printf to print a simple string is the slowest way to do it (measure the clock cycles using write syscall and printf!) AND the bloated way to do it as well...

My point: If someone wants to do a program in assembly, do it in assembly without using C functions as crutches. If someone wants to learn assembly, do everything in assembly. At maximum, use a library that don't depend on C runtime to work. Doing so is cheating, not "learning"...

Ahhh... I'm not saying that C cannot be used, is the other way around... In many cases my C routines are faster than the assembly equivalent (and I have 35 years of experience with asm!). In fact, I think if you want to do a complex function in assembly, do it first in C and take a look on what a good compiler creates, THEN you can optimize by hand (if there is some space for it).

[]s
Fred
Title: Re: Help with Hello World and NASM on mingw64
Post by: Frank Kotler on January 08, 2023, 01:21:00 AM
These C compilers appear by magic, do they? Somebody must know their assembly language or the compilers wouldn't be any good, no?

What am I missing?

Best,
Frank

Title: Re: Help with Hello World and NASM on mingw64
Post by: fredericopissarra on January 08, 2023, 01:29:40 AM
Not a good argument: NASM appeared by magic as well? A C compiler must exist BEFORE assembly, because its entire source code is in C (not ASM). And what about the first assembler? Who made it and in what language?

Another demonstration showing that using printf() is a bad idea:
Code: [Select]
; cycles.asm
;
; Yep, using libc!
;
;    nasm -felf64 -o test.o test.asm
;    ld -o test ./test
;
  bits  64
  default rel

  section .bss

counter:
  resq  1

  section .rodata

hello:
  db `Hello\n`
hello_len equ $ - hello
  db  0

fmt1:
  db  `printf (%llu cycles)\n`,0
fmt2:
  db  `sys_write (%llu cycles)\n`,0

  section .text

  extern printf

  global  main

main:
  sub   rsp,8

  ; Measuring printf call.
  xor   eax,eax
  cpuid                 ; serialize processor.
  rdtsc
  mov   [counter],eax
  mov   [counter+4],edx

  xor   eax,eax
  lea   rdi,[hello]
  call  printf wrt ..plt

  rdtscp
  sub   eax,[counter]
  sbb   edx,[counter+4]

  shl   rdx,32
  mov   esi,eax
  add   rsi,rdx
  xor   eax,eax
  lea   rdi,[fmt1]
  call  printf wrt ..plt

  ; Measuring sys_write.
  xor   eax,eax
  cpuid                 ; serialize processor
  rdtsc
  mov   [counter],eax
  mov   [counter+4],edx

  mov   eax,1
  mov   edi,eax
  lea   rsi,[hello]
  mov   edx,hello_len
  syscall

  rdtscp
  sub   eax,[counter]
  sbb   edx,[counter+4]

  shl   rdx,32
  mov   esi,eax
  add   rsi,rax
  xor   eax,eax
  lea   rdi,[fmt2]
  call  printf wrt ..plt

  add   rsp,8
  ret

Code: [Select]
$ ./cycles
Hello
printf (215525 cycles)
Hello
sys_write (11004 cycles)
Title: Re: Help with Hello World and NASM on mingw64
Post by: Frank Kotler on January 08, 2023, 02:37:30 AM
Quote
Not a good argument: NASM appeared by magic as well?

Of course not.  Simon Tatham (and Julian Hall) worked hard to  produce it.

Quote
A C compiler must exist BEFORE assembly, because its entire source code is in C (not ASM)

True of Nasm, yes. But...

Quote
. And what about the first assembler? Who made it and in what language?

Now that's a good question! Surely not C! Bare byte machine code, I would assume...

C, I understand, followed A and B... probably written in an AT&T assembler?

Quote
Another demonstration showing that using printf() is a bad idea:

I don't disagree with that. If you want printf to work in Windows, you use a library for Windows. If you want printf to work in Linux, you use a library for Linux. Etc. That's why Nasm is in C. Not for optimized code!

I dunno, Fred. I think we may appear to be arguing about something we actually agree about...

I appreciate your input!

Best,
Frank

Title: Re: Help with Hello World and NASM on mingw64
Post by: alCoPaUL on January 09, 2023, 12:14:18 AM
k.

this is the original source made from NASM

~~~~~~~~~
;
; sp4ce.asm
;
; alCoPaUL [GIMO][As][aBrA][NPA][b8]
; 10/6/2021
;
; nasm <dash>f win32 sp4ce.asm
; link sp4ce.obj /subsystem:console /defaultlib:msvcrt.lib /entry:m
;
global m
extern _printf
section .text
m:mov al,10
mov bl,45
z:lea edx,a
mov cx,491
r:cmp byte[edx],bl
je s
jmp u
s:mov byte[edx],al
u:inc edx
dec cx
cmp cx,0
jnz r
push a
push i
call _printf
mov al,10
cmp bl,45
xchg al,bl
je z
push x
push i
call _printf
ret
section .data
x:db 2Ch,32h,37h,68h,2Ch,30h,0
i:db 25h,73h,0
a:db ';-; sp4ce.asm-;-; alCoPaUL [GIMO][As][aBrA][NPA][b8]-; 10/6/2021-;-; nasm <dash>f win32 sp4ce.asm-; link sp4ce.obj /subsystem:console /defaultlib:msvcrt.lib /entry:m-;-global m-extern _printf-section .text-m:mov al,10-mov bl,45-z:lea edx,a-mov cx,491-r:cmp byte[edx],bl-je s-jmp u-s:mov byte[edx],al-u:inc edx-dec cx-cmp cx,0-jnz r-push a-push i-call _printf-mov al,10-cmp bl,45-xchg al,bl-je z-push x-push i-call _printf-ret-section .data-x:db 2Ch,32h,37h,68h,2Ch,30h,0-i:db 25h,73h,0-a:db ',27h,0

~~~~~~~~~~~~~


this is the source generated from IDA..

;
; +-------------------------------------------------------------------------+
; |      This file was generated by The Interactive Disassembler (IDA)      |
; |           Copyright (c) 2019 Hex-Rays, <support@hex-rays.com>           |
; |                      License info: 48-256C-4840-25                      |
; |                     Team-IRA Release [PUBLIC] ,v1.0                     |
; +-------------------------------------------------------------------------+
;
; Input SHA256 : 15AFA3253DA6552C06CF72B15E59D8E7FB98F58D99C0A21F3B6BA529C535165E
; Input MD5    : 9A87262B71B81E2FCD380239CBB560A2
; Input CRC32  : 010A3443

; File Name   : C:\Users\IWAYWarrior\Downloads\Project159_Windows11_NASM_VS2029\e\et\sp4ce.exe
; Format      : Portable executable for 80386 (PE)
; Imagebase   : 400000
; Timestamp   : 616720C4 (Wed Oct 13 18:09:08 2021)
; Section 1. (virtual address 00001000)
; Virtual size                  : 0000004D (     77.)
; Section size in file          : 00000200 (    512.)
; Offset to raw data for section: 00000400
; Flags 60000020: Text Executable Readable
; Alignment     : default

.686p
.mmx
.model flat


; Segment type: Pure code
; Segment permissions: Read/Execute
_text segment para public 'CODE' use32
assume cs:_text
;org 401000h
assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing



public start
start proc near
mov     al, 0Ah
mov     bl, 2Dh ; '-'

loc_401004:
lea     edx, aSp4ceAsmAlcopa ; ";-; sp4ce.asm-;-; alCoPaUL [GIMO][As][a"...
mov     cx, 1EBh

loc_40100E:
cmp     [edx], bl
jz      short loc_401014
jmp     short loc_401016

loc_401014:
mov     [edx], al

loc_401016:
inc     edx
dec     cx
cmp     cx, 0
jnz     short loc_40100E
push    offset aSp4ceAsmAlcopa ; ";-; sp4ce.asm-;-; alCoPaUL [GIMO][As][a"...
push    offset Format   ; "%s"
call    printf
mov     al, 0Ah
cmp     bl, 2Dh ; '-'
xchg    al, bl
jz      short loc_401004
push    offset a27h0    ; ",27h,0"
push    offset Format   ; "%s"
call    printf
retn
start endp ; sp-analysis failed

; [00000006 BYTES: COLLAPSED FUNCTION printf. PRESS CTRL-NUMPAD+ TO EXPAND]
align 200h
dd 380h dup(?)
_text ends

; Section 2. (virtual address 00002000)
; Virtual size                  : 00000160 (    352.)
; Section size in file          : 00000200 (    512.)
; Offset to raw data for section: 00000600
; Flags 40000040: Data Readable
; Alignment     : default
;
; Imports from MSVCR100.dll
;

; Segment type: Externs
; _idata
; int printf(const char *const Format, ...)
extrn __imp_printf:dword


; Debug Directory entries

; Segment type: Pure data
; Segment permissions: Read
_rdata segment para public 'DATA' use32
assume cs:_rdata
;org 402008h
dd 0                    ; Characteristics
dd 616720C4h            ; TimeDateStamp: Wed Oct 13 18:09:08 2021
dw 0                    ; MajorVersion
dw 0                    ; MinorVersion
dd 0Dh                  ; Type: IMAGE_DEBUG_TYPE_POGO
dd 0DCh                 ; SizeOfData
dd rva unk_40203C       ; AddressOfRawData
dd 63Ch                 ; PointerToRawData
db  18h
db    0
db    0
db    0
db    0
db  80h ; €
db    0
db  80h ; €
db    0
db    0
db    0
db    0
db    0
db    0
db    0
db    0
db    0
db    0
db    0
db    0
db    0
db    0
db    0
db    0
; Debug information (IMAGE_DEBUG_TYPE_POGO)
unk_40203C db    0
db    0
db    0
db    0
db    0
db  10h
db    0
db    0
db  47h ; G
db    0
db    0
db    0
db  2Eh ; .
db  74h ; t
db  65h ; e
db  78h ; x
db  74h ; t
db    0
db    0
db    0
db  47h ; G
db  10h
db    0
db    0
db    6
db    0
db    0
db    0
db  2Eh ; .
db  74h ; t
db  65h ; e
db  78h ; x
db  74h ; t
db  24h ; $
db  6Dh ; m
db  6Eh ; n
db    0
db    0
db    0
db    0
db    0
db  20h
db    0
db    0
db    8
db    0
db    0
db    0
db  2Eh ; .
db  69h ; i
db  64h ; d
db  61h ; a
db  74h ; t
db  61h ; a
db  24h ; $
db  35h ; 5
db    0
db    0
db    0
db    0
db    8
db  20h
db    0
db    0
db  1Ch
db    0
db    0
db    0
db  2Eh ; .
db  72h ; r
db  64h ; d
db  61h ; a
db  74h ; t
db  61h ; a
db    0
db    0
db  24h ; $
db  20h
db    0
db    0
db  18h
db    0
db    0
db    0
db  2Eh ; .
db  72h ; r
db  64h ; d
db  61h ; a
db  74h ; t
db  61h ; a
db  24h ; $
db  76h ; v
db  6Fh ; o
db  6Ch ; l
db  74h ; t
db  6Dh ; m
db  64h ; d
db    0
db    0
db    0
db  3Ch ; <
db  20h
db    0
db    0
db 0DCh ; Ü
db    0
db    0
db    0
db  2Eh ; .
db  72h ; r
db  64h ; d
db  61h ; a
db  74h ; t
db  61h ; a
db  24h ; $
db  7Ah ; z
db  7Ah ; z
db  7Ah ; z
db  64h ; d
db  62h ; b
db  67h ; g
db    0
db    0
db    0
db  18h
db  21h ; !
db    0
db    0
db  14h
db    0
db    0
db    0
db  2Eh ; .
db  69h ; i
db  64h ; d
db  61h ; a
db  74h ; t
db  61h ; a
db  24h ; $
db  32h ; 2
db    0
db    0
db    0
db    0
db  2Ch ; ,
db  21h ; !
db    0
db    0
db  14h
db    0
db    0
db    0
db  2Eh ; .
db  69h ; i
db  64h ; d
db  61h ; a
db  74h ; t
db  61h ; a
db  24h ; $
db  33h ; 3
db    0
db    0
db    0
db    0
db  40h ; @
db  21h ; !
db    0
db    0
db    8
db    0
db    0
db    0
db  2Eh ; .
db  69h ; i
db  64h ; d
db  61h ; a
db  74h ; t
db  61h ; a
db  24h ; $
db  34h ; 4
db    0
db    0
db    0
db    0
db  48h ; H
db  21h ; !
db    0
db    0
db  18h
db    0
db    0
db    0
db  2Eh ; .
db  69h ; i
db  64h ; d
db  61h ; a
db  74h ; t
db  61h ; a
db  24h ; $
db  36h ; 6
db    0
db    0
db    0
db    0
db    0
db  30h ; 0
db    0
db    0
db 0F7h ; ÷
db    1
db    0
db    0
db  2Eh ; .
db  64h ; d
db  61h ; a
db  74h ; t
db  61h ; a
db    0
db    0
db    0
__IMPORT_DESCRIPTOR_MSVCR100 dd rva off_402140 ; Import Name Table
dd 0                    ; Time stamp
dd 0                    ; Forwarder Chain
dd rva aMsvcr100Dll     ; DLL Name
dd rva __imp_printf     ; Import Address Table
align 20h
;
; Import names for MSVCR100.dll
;
off_402140 dd rva word_402148
dd 0
word_402148 dw 5D7h
db 'printf',0
align 2
aMsvcr100Dll db 'MSVCR100.dll',0
align 1000h
_rdata ends

; Section 3. (virtual address 00003000)
; Virtual size                  : 000001F7 (    503.)
; Section size in file          : 00000200 (    512.)
; Offset to raw data for section: 00000800
; Flags C0000040: Data Readable Writable
; Alignment     : default

; Segment type: Pure data
; Segment permissions: Read/Write
_data segment para public 'DATA' use32
assume cs:_data
;org 403000h
a27h0 db ',27h,0',0
; char Format[]
Format db '%s',0
aSp4ceAsmAlcopa db ';-; sp4ce.asm-;-; alCoPaUL [GIMO][A'
db 's][aBrA][NPA][b8]-; 10/6/2021-;-; n'
db 'asm <dash>f win32 sp4ce.asm-; link '
db 'sp4ce.obj /subsystem:console /defau'
db 'ltlib:msvcrt.lib /entry:m-;-global '
db 'm-extern _printf-section .text-m:mo'
db 'v al,10-mov bl,45-z:lea edx,a-mov c'
db 'x,491-r:cmp byte[edx],bl-je s-jmp u'
db '-s:mov byte[edx],al-u:inc edx-dec c'
db 'x-cmp cx,0-jnz r-push a-push i-call'
db ' _printf-mov al,10-cmp bl,45-xchg a'
db 'l,bl-je z-push x-push i-call _print'
db 'f-ret-section .data-x:db 2Ch,32h,37'
db 'h,68h,2Ch,30h,0-i:db 25h,73h,0-a:db'
db ' ',27h,0
align 1000h
_data ends


end start

~~~~~~

so printf() is not broken down to pieces as you imply BUT is listed "by function" for EXTERNAL use,

as i saw, you converted the .asm object file to linux executable using GCC and compared it to the generated linux executable with different routines (with SYSCALL) to display texts using ld. you can link your print() assembled file using ld.exe WITH the appropriate C runtime library with your linux object file. try that and compare again,.

edit: the actual runtime for executing the code is MSVCR100.dll and you need to link the .obj file to the generic .dll file for the appropriate runtime file version (e.g. msvcrt.dll for Visual Studio 2010 C/C++).
edit1: grammar, etc.
Title: Re: Help with Hello World and NASM on mingw64
Post by: alCoPaUL on January 09, 2023, 12:52:32 AM
and to add.

you saw that the source that i posted with printf() is not made with #include <whatever> and curly braces. it uses opcodes and numbers.

and you sound that you're complaining for the fact that printf() did some epic stuff so you wanna discredit it by comparing an assembled code with printf() that you linked with GCC to an assembled code with SYSCALL and linking it with ld.exe.

as i said, try linking your printf() assembled file with ld.exe coz you can do that.

like yo, you've programmed assembly for 35 years and suddenly an assembly code using printf() is not assembly language??

like wtf lelz men.
Title: Re: Help with Hello World and NASM on mingw64
Post by: fredericopissarra on January 09, 2023, 09:48:55 AM
Let's play a game then... Let's make a small program. You do your way, I do mine...
Wins who made them SMALLER and running FASTER.
And for Windows (argh!)...

I'll wait for a proposal of what to do...

BTW: That code above doesn't work (pushing arguments to _printf and not correcting ESP after the call will cause a seg fault). There are other errors.

I'll show what you're doing wrong with that IDA listing later (When I got my hands on WINDOWS and VS - I don't have them at home).
Title: Re: Help with Hello World and NASM on mingw64
Post by: fredericopissarra on January 09, 2023, 12:07:12 PM
BWAHAHAHAHAHAHAHAHA... Your code isn't compiling! There is no _printf on MSVCRT!
Code: [Select]
C:\Windows\System32>dumpbin /exports msvcr100.dll | findstr _printf
        640  27F 000656F1 _get_printf_count_output
        981  3D4 0006564C _printf_l
        982  3D5 000656AF _printf_p
        983  3D6 00065696 _printf_p_l
        984  3D7 00065665 _printf_s_l
       1031  406 000656C7 _set_printf_count_output
Same for msvcrt.dll

Code: [Select]
C:\Work\tmp> link test.obj /defaultlib:msvcrt.lib /subsystem:console
link test.obj /defaultlib:msvcrt.lib /entry:start /subsystem:console /entry:start
Microsoft (R) Incremental Linker Version 14.29.30147.0
Copyright (C) Microsoft Corporation.  All rights reserved.

test.obj : error LNK2001: símbolo externo não resolvido _printf
test.exe : fatal error LNK1120: 1 externo não resolvidos
Yep... LIB and INCLUDE environment vars are correct.
Title: Re: Help with Hello World and NASM on mingw64
Post by: fredericopissarra on January 09, 2023, 03:40:02 PM
Here's how to do it:
Code: [Select]
; test.asm
;
;   nasm -fwin32 -o test.obj test.asm
;   link test.obj /debug:none /release /subsystem:console msvcrt.lib legacy_stdio_definitions.lib
;

  bits  32

  section .rodata

str:
  db  `Hello\n`,0

  section .text

  ; Older MSVCRT exports _cprintf, but you must link with legacy_stdio_definitions.lib.
  extern __cprintf

  global _main

  align 4
_main:
  push  str
  call  __cprintf
  add   esp,4
  ret
Now, take a look at:
Code: [Select]
C:\Work> dumpbin /disasm test.exe3308 bytes in .text, 512 bytes in .data, 2704 bytes in .rodata and 344 in relocations in a simple 'Hello world' program. And lots of code!

Now, this one, to mimic your previous code (with CORRECTIONS):
Code: [Select]
; test.asm
;
; Better approach WITHOUT using libc!
; Why better? Because this code don't need to load MSVCRT???.DLL and all C initialization code.
;
; Unfortunately Windows Console applications must use Console API from kernel32.dll.
;
;   nasm -fwin32 hello.asm -o hello.o
;
;   if using Visual Studio:
;     link hello.o /debug:none /release /subsystem:console /defaultlib:kernel32.lib /entry:start
;   or, with mingw32:
;     ld -s -o hello.exe hello.o -lkernel32
;
; They will create the same image...
;

  ; Yep, it is the default, but I like to be explicit.
  bits  32

  ; Handle put in .bss not to occupy space in the image.
  section .bss

handle:
  resd  1

  ; Notice these buffers won't be changed!
  section .rodata

; Little test: Will change '-' to `\r\n` on terminal.
str:
  db  `Hello-World-`
str_len equ $ - str

crlf:
  db  `\r\n`
crlf_len equ $ - crlf

  section .text

  ; As defined in Win32 Console API.
  %define STD_OUTPUT_HANDLE -11

  extern __imp__GetStdHandle@4
  extern __imp__WriteConsoleA@20
  extern __imp__ExitProcess@4

  global _start

  align 4         ; always a good ideia to align entrypoints.
_start:
  %ifdef OBEY_ABI
    push  ebx       ; Obey MS-ABI and preserve EBX and EDI!
    push  edi       ; Not really necessary here!
  %endif

  ; Gets STDOUT_HANDLE from Console API.
  push  byte STD_OUTPUT_HANDLE
  call  [__imp__GetStdHandle@4]
  mov   [handle],eax
 
  ; prepare to scan the string searching for '-' in the loop below.
  lea   edi,[str]
  mov   ecx,str_len

  align 4             ; always a good idea to align LOOPs entrypoints.
.loop:
  mov   al,'-'
  mov   ebx,edi       ; keep track of the substring start
  repne scasb
  jne   .exit         ; Not found, exit the loop.

  call  print_substring
  call  print_crlf
  jmp   .loop
.exit:

  ; --- Exit from program
  %ifdef OBEY_ABI
    pop   edi           ; Restore EBX and EDI.
    pop   ebx           ; Not really necessary here!
  %endif

  ; Don't need to close the stdout handle!

  ; Must exit jumping to ExitProceess!
  push  byte 0
  jmp   [__imp__ExitProcess@4]

; Prints the substring not including the '-' found.
; Entry: EBX = start of substring,
;        EDI = one char past the '-' found.
; Destroys EAX (at least).
; Preserve ECX to continue scanning.
  align 4
print_substring:
  push  ecx

  lea   eax,[edi-1]
  sub   eax,ebx
  jz    .exit

  push  byte 0
  push  byte 0
  push  eax
  push  ebx
  push  dword [handle]
  call  [__imp__WriteConsoleA@20] ; Since ABI allows changes no ECX it was preserved earlier.
.exit:
  pop   ecx
  ret

; Just print CRLF. Preserve ECX to conitnue scanning.
  align 4
print_crlf:
  push  ecx
 
  push  byte 0
  push  byte 0
  push  crlf_len
  push  crlf
  push  dword [handle]
  call  [__imp__WriteConsoleA@20] ; Since ABI allows changes no ECX it was preserved earlier.

  pop   ecx
  ret
124 bytes in .text, 0 bytes in .data, 4 bytes in .bss, 14 bytes in .rodata, 28 bytes in relocations (7 relocations), and 94 bytes in imported ptrs (from kernel32.dll)...
Code: [Select]
C:\Work> dir *.exe
 Volume in drive C is OS
 Volume Serial Number is 9E55-4C71

 Directory of C:\Work

09/01/2023  12:03             3.072 test.exe
09/01/2023  12:31             9.216 test2.exe
Again, 6 KiB of unecessary code and data to initialize libc... blagh!

Title: Re: Help with Hello World and NASM on mingw64
Post by: alCoPaUL on January 09, 2023, 04:30:55 PM
~~~~~~~~~
;
; sp4ce.asm
;
; alCoPaUL [GIMO][As][aBrA][NPA][b8]
; 10/6/2021
;
; nasm <dash>f win32 sp4ce.asm
; link sp4ce.obj /subsystem:console /defaultlib:msvcrt.lib /entry:m
;

you need msvcrt.lib..

bro, like wtf.. of course my code isn't compiling coz it's assembling..

go get the sdk for visual studio 2010 and get the appropriate .libs
Title: Re: Help with Hello World and NASM on mingw64
Post by: alCoPaUL on January 09, 2023, 04:36:49 PM
and yo, did you even compare my posted source code, like the way it was written or how the control flow flows to your almost linear assembly structure?

like if you didn't delete my post in the EXAMPLE CODE section and actually tested it in a spare isolated computer, you should've had everything there to assemble properly and see what's up.

printf() is not that different with win32 apis. you can find printf() in the runtime dll, you can find win32 api from kernel32.dll

in linux, you just go syscalling forever to meet your needs (at least ms-dos goes INT (number here))

Title: Re: Help with Hello World and NASM on mingw64
Post by: alCoPaUL on January 09, 2023, 04:39:12 PM
and again, you can use ld.exe with the appropriate C runtime lib in linux to link your nasm assembly object code that has printf().

you were insisting that those files are the same coz why? you used GCC in both - the C printf() hello world template and the assembly language code with printf().

and bro, you had the audacity to compare the file size of the assembly file that has printf() that you GCCed and the one that you LDed that has the SYSCALL meme.

go link the assembly code that has the printf() using LD.exe with it's appropriate library and let's talk after.