webentwicklung-frage-antwort-db.com.de

Wie schreibe ich Hallo Welt in Assembler unter Windows?

Ich wollte etwas Grundlegendes in Assembly unter Windows schreiben, ich verwende NASM, aber ich kann nichts zum Laufen bringen.

Wie kann man Hallo Welt ohne die Hilfe von C-Funktionen unter Windows schreiben und kompilieren?

80
feiroox

NASM-Beispiele .

Aufruf von libc stdio printf, Implementierung von 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

Dann renne

nasm -fwin32 helloworld.asm
gcc helloworld.obj
a

Es gibt auch The Clueless Newbies Guide zu Hello World in Nasm ohne die Verwendung einer C-Bibliothek. Dann würde der Code so aussehen.

16-Bit-Code mit MS-DOS-Systemaufrufen: Funktioniert in DOS-Emulatoren oder in 32-Bit-Windows mit NTVDM-Unterstützung . Kann unter keinem 64-Bit-Windows "direkt" (transparent) ausgeführt werden, da ein x86-64-Kernel den vm86-Modus nicht verwenden kann.

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

Bauen Sie dies in eine ausführbare Datei .com Ein, so dass sie mit cs:100h Geladen wird, wobei alle Segmentregister gleich sind (winziges Speichermodell).

Viel Glück.

28
anderstornvig

In diesem Beispiel wird gezeigt, wie Sie direkt zur Windows-API und nicht zur Verknüpfung in der C-Standardbibliothek wechseln.

    global _main
    extern  [email protected]
    extern  [email protected]
    extern  [email protected]

    section .text
_main:
    ; DWORD  bytes;    
    mov     ebp, esp
    sub     esp, 4

    ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
    Push    -11
    call    [email protected]
    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    [email protected]

    ; ExitProcess(0)
    Push    0
    call    [email protected]

    ; never here
    hlt
message:
    db      'Hello, World', 10
message_end:

Zum Kompilieren benötigen Sie NASM und LINK.EXE (aus Visual Studio Standard Edition).

 nasm -fwin32 hello.asm 
 Link/Subsystem: console/nodefaultlib/Eintrag: main hello.obj 
114
caffiend

Dies sind Win32- und Win64-Beispiele mit Windows-API-Aufrufen. Sie sind eher für MASM als für NASM, aber schauen Sie sie sich an. Weitere Details finden Sie in this Artikel.

;---ASM Hello World Win32 MessageBox

.386
.model flat, stdcall
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib

.data
title db 'Win32', 0
msg db 'Hello World', 0

.code

Main:
Push 0            ; uType = MB_OK
Push offset title ; LPCSTR lpCaption
Push offset msg   ; LPCSTR lpText
Push 0            ; hWnd = HWND_DESKTOP
call MessageBoxA
Push eax          ; uExitCode = MessageBox(...)
call ExitProcess

End Main

;---ASM Hello World Win64 MessageBox

extrn MessageBoxA: PROC
extrn ExitProcess: PROC

.data
title db 'Win64', 0
msg db 'Hello World!', 0

.code
main proc
  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     ; uExitCode = MessageBox(...)
  call ExitProcess
main endp

End

Um diese mit MASM zusammenzustellen und zu verknüpfen, verwenden Sie diese Option für ausführbare 32-Bit-Dateien:

ml.exe [filename] /link /subsystem:windows 
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main

oder dies für 64-bit ausführbare Dateien:

ml64.exe [filename] /link /subsystem:windows 
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main
17
PhiS

Flat Assembler benötigt keinen zusätzlichen Linker. Dies macht die Assembler-Programmierung sehr einfach. Es ist auch für Linux verfügbar.

Das ist hello.asm aus den Fasm-Beispielen:

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 erstellt eine ausführbare Datei:

> fasm hello.asm 
 Flat Assembler Version 1.70.03 (1048575 Kilobyte Speicher) 
 4 Durchgänge, 1536 Bytes 

Und das ist das Programm in IDA :

enter image description here

Sie können die drei Aufrufe sehen: GetCommandLine, MessageBox und ExitProcess.

13
ceving

Um eine .exe mit NASM'compiler und dem Linker von Visual Studio zu erhalten, funktioniert dieser Code einwandfrei:

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

Wenn dieser Code z. "test64.asm", dann kompilieren:

nasm -f win64 test64.asm

Produziert "test64.obj". Verlinken Sie anschließend über die Eingabeaufforderung:

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

wo path_to_link sein könnte C:\Programme (x86)\Microsoft Visual Studio 10.0\VC\bin oder wo immer sich Ihr link.exe-Programm auf Ihrem Computer befindet, path_to_libs könnte sein C :\Programme (x86)\Windows Kits\8.1\Lib\winv6.3\um\x64 oder wo immer sich Ihre Bibliotheken befinden (in diesem Fall sind sowohl kernel32.lib als auch user32.lib aktiviert) Verwenden Sie andernfalls eine Option für jeden von Ihnen benötigten Pfad.) und die Option /largeaddressaware: no ist erforderlich, um zu vermeiden, dass sich Linker über zu lange Adressen beschweren. für user32.lib in diesem Fall). Wenn der Linker von Visual über die Eingabeaufforderung aufgerufen wird, muss die Umgebung zuvor eingerichtet werden (einmalige Ausführung von vcvarsall.bat und/oder siehe MS C++ 2010 und mspdb100.dll ). .

10
rarias

Es sei denn, Sie rufen einige - Funktion auf, ist dies überhaupt nicht trivial. (Und im Ernst, es gibt keinen wirklichen Unterschied in der Komplexität zwischen dem Aufrufen von printf und dem Aufrufen einer Win32-API-Funktion.)

Sogar DOS int 21h ist eigentlich nur ein Funktionsaufruf, auch wenn es sich um eine andere API handelt.

Wenn Sie dies ohne Hilfe tun möchten, müssen Sie direkt mit Ihrer Videohardware sprechen und wahrscheinlich Bitmaps der Buchstaben von "Hello world" in einen Framebuffer schreiben. Selbst dann übernimmt die Grafikkarte die Umwandlung dieser Speicherwerte in VGA/DVI-Signale.

Beachten Sie, dass keines dieser Dinge bis hinunter zur Hardware in ASM interessanter ist als in C. Ein "Hallo Welt" -Programm läuft auf einen Funktionsaufruf hinaus. Eine nette Sache bei ASM ist, dass Sie jede beliebige ABI verwenden können, die Sie möchten. Sie müssen nur wissen, was das ABI ist.

5

Wenn Sie NASM und den Linker (link.exe) von Visual Studio mit dem Hello World-Beispiel von anderstornvig verwenden möchten, müssen Sie manuell eine Verknüpfung mit der C-Laufzeitbibliothek herstellen, die die Funktion printf () enthält.

nasm -fwin32 helloworld.asm
link.exe helloworld.obj libcmt.lib

Hoffe das hilft jemandem.

4
tboerman

Die besten Beispiele sind solche mit FASM, da FASM keinen Linker verwendet, der die Komplexität der Windows-Programmierung durch eine weitere undurchsichtige Komplexitätsebene verbirgt. Wenn Sie mit einem Programm zufrieden sind, das in ein GUI-Fenster schreibt, finden Sie ein Beispiel dafür im Beispielverzeichnis von fasm.

Wenn Sie ein Konsolenprogramm möchten, das die Umleitung von Standard-In und Standard-Out ermöglicht, ist dies ebenfalls möglich. Es gibt ein (nicht triviales) Beispielprogramm, das keine GUI verwendet und ausschließlich mit der Konsole zusammenarbeitet, die selbst fasm ist. Dies kann auf das Wesentliche reduziert werden. (Ich habe einen vierten Compiler geschrieben, der ein weiteres Nicht-GUI-Beispiel darstellt, aber auch nicht trivial ist.).

Ein solches Programm hat den folgenden Befehl, um einen richtigen ausführbaren Header zu generieren, der normalerweise von einem Linker ausgeführt wird.

FORMAT PE CONSOLE 

Ein Abschnitt namens '.idata' enthält eine Tabelle, die Windows beim Start hilft, Funktionsnamen mit den Laufzeitenadressen zu koppeln. Es enthält außerdem einen Verweis auf KERNEL.DLL, bei dem es sich um das Windows-Betriebssystem handelt.

 section '.idata' import data readable writeable
    dd 0,0,0,rva kernel_name,rva kernel_table
    dd 0,0,0,0,0

  kernel_table:
    [email protected]    DD rva _ExitProcess
    CreateFile        DD rva _CreateFileA
        ...
        ...
    [email protected]   DD rva _GetStdHandle
                      DD 0

Das Tabellenformat wird von Windows vorgegeben und enthält Namen, die beim Programmstart in Systemdateien nachgeschlagen werden. FASM verbirgt einen Teil der Komplexität hinter dem Schlüsselwort rva. _ExitProcess @ 4 ist also ein FASM-Label und _exitProcess ist ein String, der von Windows nachgeschlagen wird.

Ihr Programm befindet sich in der Sektion '.text'. Wenn Sie diesen Abschnitt als lesbar, beschreibbar und ausführbar deklarieren, ist dies der einzige Abschnitt, den Sie hinzufügen müssen.

    section '.text' code executable readable writable

Sie können alle im Abschnitt .idata deklarierten Einrichtungen anrufen. Für ein Konsolenprogramm benötigen Sie _GetStdHandle, um die Dateideskriptoren für standard in und standardout zu finden (mit symbolischen Namen wie STD_INPUT_HANDLE, die fasm in der Include-Datei win32a.inc findet). Sobald Sie die Dateideskriptoren haben, können Sie WriteFile und ReadFile ausführen. Alle Funktionen sind in der kernel32-Dokumentation beschrieben. Sie sind sich dessen wahrscheinlich bewusst, oder Sie würden nicht versuchen, Assembler zu programmieren.

Zusammenfassend: Es gibt eine Tabelle mit ASCII-Namen, die mit dem Windows-Betriebssystem gekoppelt sind. Beim Start wird dies in eine Tabelle mit aufrufbaren Adressen umgewandelt, die Sie in Ihrem Programm verwenden.