How to write hello world in assembler under Windows?

前端 未结 8 913
情书的邮戳
情书的邮戳 2020-11-22 12:01

I wanted to write something basic in assembly under Windows, I\'m using NASM, but I can\'t get anything working.

How to write and compile hello world without the he

相关标签:
8条回答
  • 2020-11-22 12:30

    Flat Assembler does not need an extra linker. This makes assembler programming quite easy. It is also available for Linux.

    This is hello.asm from the Fasm examples:

    include 'win32ax.inc'
    
    .code
    
      start:
        invoke  MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK
        invoke  ExitProcess,0
    
    .end start
    

    Fasm creates an executable:

    >fasm hello.asm
    flat assembler  version 1.70.03  (1048575 kilobytes memory)
    4 passes, 1536 bytes.
    

    And this is the program in IDA:

    enter image description here

    You can see the three calls: GetCommandLine, MessageBox and ExitProcess.

    0 讨论(0)
  • 2020-11-22 12:34

    To get an .exe with NASM'compiler and Visual Studio's linker this code works fine:

    global WinMain
    extern ExitProcess  ; external functions in system libraries 
    extern MessageBoxA
    
    section .data 
    title:  db 'Win64', 0
    msg:    db 'Hello world!', 0
    
    section .text
    WinMain:
        sub rsp, 28h  
        mov rcx, 0       ; hWnd = HWND_DESKTOP
        lea rdx,[msg]    ; LPCSTR lpText
        lea r8,[title]   ; LPCSTR lpCaption
        mov r9d, 0       ; uType = MB_OK
        call MessageBoxA
        add rsp, 28h  
    
        mov  ecx,eax
        call ExitProcess
    
        hlt     ; never here
    

    If this code is saved on e.g. "test64.asm", then to compile:

    nasm -f win64 test64.asm
    

    Produces "test64.obj" Then to link from command prompt:

    path_to_link\link.exe test64.obj /subsystem:windows /entry:WinMain  /libpath:path_to_libs /nodefaultlib kernel32.lib user32.lib /largeaddressaware:no
    

    where path_to_link could be C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin or wherever is your link.exe program in your machine, path_to_libs could be C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x64 or wherever are your libraries (in this case both kernel32.lib and user32.lib are on the same place, otherwise use one option for each path you need) and the /largeaddressaware:no option is necessary to avoid linker's complain about addresses to long (for user32.lib in this case). Also, as it is done here, if Visual's linker is invoked from command prompt, it is necessary to setup the environment previously (run once vcvarsall.bat and/or see MS C++ 2010 and mspdb100.dll).

    0 讨论(0)
  • 2020-11-22 12:36

    NASM examples.

    Calling libc stdio printf, implementing int main(){ return printf(message); }

    ; ----------------------------------------------------------------------------
    ; 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.
    ; ----------------------------------------------------------------------------
    
        global  _main
        extern  _printf
    
        section .text
    _main:
        push    message
        call    _printf
        add     esp, 4
        ret
    message:
        db  'Hello, World', 10, 0
    

    Then run

    nasm -fwin32 helloworld.asm
    gcc helloworld.obj
    a
    

    There's also The Clueless Newbies Guide to Hello World in Nasm without the use of a C library. Then the code would look like this.

    16-bit code with MS-DOS system calls: works in DOS emulators or in 32-bit Windows with NTVDM support. Can't be run "directly" (transparently) under any 64-bit Windows, because an x86-64 kernel can't use vm86 mode.

    org 100h
    mov dx,msg
    mov ah,9
    int 21h
    mov ah,4Ch
    int 21h
    msg db 'Hello, World!',0Dh,0Ah,'$'
    

    Build this into a .com executable so it will be loaded at cs:100h with all segment registers equal to each other (tiny memory model).

    Good luck.

    0 讨论(0)
  • 2020-11-22 12:38

    This example shows how to go directly to the Windows API and not link in the C Standard Library.

        global _main
        extern  _GetStdHandle@4
        extern  _WriteFile@20
        extern  _ExitProcess@4
    
        section .text
    _main:
        ; DWORD  bytes;    
        mov     ebp, esp
        sub     esp, 4
    
        ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
        push    -11
        call    _GetStdHandle@4
        mov     ebx, eax    
    
        ; WriteFile( hstdOut, message, length(message), &bytes, 0);
        push    0
        lea     eax, [ebp-4]
        push    eax
        push    (message_end - message)
        push    message
        push    ebx
        call    _WriteFile@20
    
        ; ExitProcess(0)
        push    0
        call    _ExitProcess@4
    
        ; never here
        hlt
    message:
        db      'Hello, World', 10
    message_end:
    

    To compile, you'll need NASM and LINK.EXE (from Visual studio Standard Edition)

       nasm -fwin32 hello.asm
       link /subsystem:console /nodefaultlib /entry:main hello.obj 
    
    0 讨论(0)
  • 2020-11-22 12:39

    The best examples are those with fasm, because fasm doesn't use a linker, which hides the complexity of windows programming by another opaque layer of complexity. If you're content with a program that writes into a gui window, then there is an example for that in fasm's example directory.

    If you want a console program, that allows redirection of standard in and standard out that is also possible. There is a (helas highly non-trivial) example program available that doesn't use a gui, and works strictly with the console, that is fasm itself. This can be thinned out to the essentials. (I've written a forth compiler which is another non-gui example, but it is also non-trivial).

    Such a program has the following command to generate a proper header for 32-bit executable, normally done by a linker.

    FORMAT PE CONSOLE 
    

    A section called '.idata' contains a table that helps windows during startup to couple names of functions to the runtimes addresses. It also contains a reference to KERNEL.DLL which is the Windows Operating System.

     section '.idata' import data readable writeable
        dd 0,0,0,rva kernel_name,rva kernel_table
        dd 0,0,0,0,0
    
      kernel_table:
        _ExitProcess@4    DD rva _ExitProcess
        CreateFile        DD rva _CreateFileA
            ...
            ...
        _GetStdHandle@4   DD rva _GetStdHandle
                          DD 0
    

    The table format is imposed by windows and contains names that are looked up in system files, when the program is started. FASM hides some of the complexity behind the rva keyword. So _ExitProcess@4 is a fasm label and _exitProcess is a string that is looked up by Windows.

    Your program is in section '.text'. If you declare that section readable writeable and executable, it is the only section you need to add.

        section '.text' code executable readable writable
    

    You can call all the facilities you declared in the .idata section. For a console program you need _GetStdHandle to find he filedescriptors for standard in and standardout (using symbolic names like STD_INPUT_HANDLE which fasm finds in the include file win32a.inc). Once you have the file descriptors you can do WriteFile and ReadFile. All functions are described in the kernel32 documentation. You are probably aware of that or you wouldn't try assembler programming.

    In summary: There is a table with asci names that couple to the windows OS. During startup this is transformed into a table of callable addresses, which you use in your program.

    0 讨论(0)
  • 2020-11-22 12:43

    Unless you call some function this is not at all trivial. (And, seriously, there's no real difference in complexity between calling printf and calling a win32 api function.)

    Even DOS int 21h is really just a function call, even if its a different API.

    If you want to do it without help you need to talk to your video hardware directly, likely writing bitmaps of the letters of "Hello world" into a framebuffer. Even then the video card is doing the work of translating those memory values into VGA/DVI signals.

    Note that, really, none of this stuff all the way down to the hardware is any more interesting in ASM than in C. A "hello world" program boils down to a function call. One nice thing about ASM is that you can use any ABI you want fairly easy; you just need to know what that ABI is.

    0 讨论(0)
提交回复
热议问题