Author Topic: 'Hello world' in NASM without using C libraries  (Read 31201 times)

Offline bf2

  • New Member
  • Posts: 1
'Hello world' in NASM without using C libraries
« on: November 27, 2010, 09:14:02 AM »
I was attracted to assembly language by the promise of freedom and I have been rudely awakened now that I have realised how hard it is to write just a 'Hello world' console program on Windows without using any C libraries.

To get around this, I even checked the DJGPP assembly listing of a simple 'Hello world' program in C, just to see if I can copy the assembly code from there. Alas that didn't work either.

My C code:
Code: [Select]
int main()
{
  printf("Hello");
  return 0;
}

Become this in the assembly listing
Code: [Select]
.file "Test.c"
.section .text
LC0:
.ascii "Hello\0"
.p2align 4,,15
.globl _main
_main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $16, %esp
pushl $LC0
call _printf
movl -4(%ebp), %ecx
xorl %eax, %eax
leave
leal -4(%ecx), %esp
ret
.ident "GCC: (GNU) 4.4.4"

It's simply calling _printf. Is there no way to write a console program in NASM that runs on Windows XP, says 'Hello world' and uses only just NASM? The C compiler is obviously doing it under the hood so of coruse can be done, but I don't know how. If the C compiler is making a Win32 call that's fine too, but I want to go as close to the source as possible.

Thanks for any help.

Offline cm

  • Jr. Member
  • *
  • Posts: 65
Re: 'Hello world' in NASM without using C libraries
« Reply #1 on: November 27, 2010, 12:25:31 PM »
I was attracted to assembly language by the promise of freedom and I have been rudely awakened now that I have realised how hard it is to write just a 'Hello world' console program on Windows without using any C libraries.

Yep, sure you get some freedom but you'll generally have to write ten times the source code and be aware of a lot more things than with HLLs.

Quote
To get around this, I even checked the DJGPP assembly listing of a simple 'Hello world' program in C, just to see if I can copy the assembly code from there. Alas that didn't work either. [...] It's simply calling _printf.

What did you expect? That's exactly what your C source did.

Besides, this isn't the full program, because the CRT will be linked in (of course including _printf's code if you use _printf). You also have to understand that _main is not a special symbol for the operating system - execution starts somewhere in the CRT startup code (this is determined by an entry point field in the executable's header) and your _main function will only be called by that code.

Quote
Is there no way to write a console program in NASM that runs on Windows XP, says 'Hello world' and uses only just NASM?

Of course there is, but it's a lot more dependant on the executable format and operating system API to use than that example. I'm sure there are some tutorials which will show you how to create Windows executables with nothing but an assembler (even some for NASM).

You can also try to search through your compiler's code to search, for example, the source code of _printf. That will no doubt contain either calls to the OS API, or (rather) to some lower-level library function. (Though DJGPP isn't for Windows programming. Why'd you use it?)
C. Masloch

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: 'Hello world' in NASM without using C libraries
« Reply #2 on: November 27, 2010, 09:57:55 PM »
It is possible to write a Windows program using "just" Nasm. You have to create the necessary headers "by hand". NaGoA has some macros to simplify it. Much more practical is to use Nasm plus a linker. Unfortunately, linkers differ, and I don't know much about 'em. Jeremy Gordon's "Golink" seems to be the popular one, these days. Long ago, I used to use Nasm's "-f obj" output mode, and Alink... with mixed success... This is an obsolete way to make a Windows file!

Code: [Select]
; nasm -f obj hwcons.asm

;%define WriteFile _WriteFile@20
    extern  WriteFile
    import WriteFile kernel32.dll

;%define ExitProcess _ExitProcess@4
    extern  ExitProcess
    import ExitProcess kernel32.dll

section _TEXT use32 class=CODE
..start

    push    dword 0
    push    dword num_chars
    push    dword MSGLEN
    push    dword msg
    push    dword -11
    call    [WriteFile]

exit_ok:
    push    dword 0
exit:
    call    [ExitProcess]

section _DATA use32 class=DATA
    num_chars       dd      0
    msg             db      'Hello, Console.', 13, 10
    MSGLEN          equ     $ - msg

That used to work, but is incorrect! This is an untested(!) attempt to correct it:

Code: [Select]
; nasm -f obj hwcons.asm
; alink -oPE hwcons.obj ? may need "-subsys:console" or something?

    extern  WriteFile
    import WriteFile kernel32.dll

extern GetStdHandle
import GetStdHandle kernel32.dll ; ?

    extern  ExitProcess
    import ExitProcess kernel32.dll

section _TEXT use32 class=CODE
..start

push -11
call [GetStdHandle]
mov [hstdout], eax

    push    dword 0
    push    dword num_chars
    push    dword MSGLEN
    push    dword msg
    push    dword [hstdout]
    call    [WriteFile]

exit_ok:
    push    dword 0
exit:
    call    [ExitProcess]

section _DATA use32 class=DATA
    num_chars       dd      0

hstdout dd 0

    msg             db      'Hello, Console.', 13, 10
    MSGLEN          equ     $ - msg

I would suggest that you figure out how to do this with "-f win32" output, if you can! "import" is known to Nasm only in "-f obj" mode. There's an "import" macro in the NASMX package - I don't think it's quite the same(?). Note that this uses "call [SomeAPI]" - in most cases, "call SomeAPI" will be correct, but this particular "style" needs the square brackets.

As Christian says, DJGPP is for 32-bit extended dos, not for Windows. You may want the "MinGW" package. It includes a port of gcc - which you probably don't want - and a port of ld, which you might want. As I recall, I never figured out where they put the libraries, but I had some success linking against "win32.lib" from Hutch's MASM32 package.

If you want to get "lower level" than "call SomeAPI", forget about Windows or any other "protected" OS - they're "protected" against US! Dos is okay - kind of a lame OS, but a very full-featured second-stage loader! :) Dos under Windows is "fake dos", and is somewhat limited in what you can do (but pretty close). Real real-mode dos is "wide open". Linux allows us to interface with the kernel with "int 80h" - which may seem a little "lower level", but really isn't - there's always a "black box" at the end of the line! With Windows, you don't have much choice but "call SomeAPI". (consult MicroSoft for the APIs and how to use 'em)

The NASMX package includes examples, but IMHO too much is "hidden" behind macros. Maybe it'll satisfy you - doesn't satisfy me. Great for "production code", not as good for learning what goes on under the hood. "push, push, push, call SomeAPI" gets old pretty quick... but "invoke" isn't a CPU instruction! Just my opinion...

Best,
Frank


Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: 'Hello world' in NASM without using C libraries
« Reply #3 on: November 28, 2010, 04:51:40 PM »
I would suggest that you figure out how to do this with "-f win32" output, if you can! "import" is known to Nasm only in "-f obj" mode. There's an "import" macro in the NASMX package - I don't think it's quite the same(?).

Nope, the import macro in NASMX is designed to work in conjunction with the calling convention of the target platform.


The NASMX package includes examples, but IMHO too much is "hidden" behind macros. Maybe it'll satisfy you - doesn't satisfy me. Great for "production code", not as good for learning what goes on under the hood. "push, push, push, call SomeAPI" gets old pretty quick... but "invoke" isn't a CPU instruction! Just my opinion...

Best,
Frank

NASMX does indeed hide all the push,push,push, call someAPI,add esp sequence of operations.  It wraps all the tedious function prologue/epilogue housekeeping with proc/invoke macros to transparently handle calling convention issues.  There are two schools of thought for using the macros:

1) You are starting out learning assembly and would rather start with figuring out what rep stosd does without trying to learn everything required to interface with the system libraries.  You just want it to work.

2) You already understand the proper sequence of operations required to call functions and would rather let the macros handle the tedious gunk that you would otherwise be required to implement over and over again yourself.

NASMX tries very hard to bring a familiar high-level language syntax to the assembly world and make it easier to develop and port your code. As NASMX is open-source you are free to delve deep into it to understand everything it does for you "under the hood" as your experience level increases.  You should definately have a thorough understanding of the nasm preprocessor before going this route.  You may prefer using it or you may not.  It's not a one size fits all package but it's available to you if you want it. ;)