Comment écrire hello world en assembleur sous Windows?
8 réponses
l'Appel de la libc stdio printf
, la mise en œuvre de 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
puis exécuter
nasm -fwin32 helloworld.asm
gcc helloworld.obj
a
Il y a aussi Les Désemparés Débutants Guide de Bonjour tout le Monde dans Msna sans l'utilisation d'une bibliothèque C de. Alors le code ressemblerait à ça.
code 16 bits avec système MS-DOS appels: Fonctionne dans les émulateurs DOS ou dans les fenêtres 32 bits avec prise en charge NTVDM . Ne peut pas être exécuté "directement" (de manière transparente) sous N'importe quelle fenêtre 64 bits, parce qu'un noyau x86-64 ne peut pas utiliser le mode vm86.
org 100h
mov dx,msg
mov ah,9
int 21h
mov ah,4Ch
int 21h
msg db 'Hello, World!',0Dh,0Ah,'$'
construisez ceci dans un .com
exécutable de sorte qu'il sera chargé à cs:100h
avec tous les registres de segments égaux les uns aux autres (modèle de mémoire minuscule).
bonne chance.
cet exemple montre comment passer directement à L'API Windows et ne pas créer de lien dans la bibliothèque standard C.
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:
pour compiler, vous aurez besoin de NASM et de LINK.EXE (de Visual studio Standard Edition)
nasm -fwin32 hello.asm link /subsystem:console /nodefaultlib /entry:main hello.obj
ce sont des exemples Win32 et Win64 utilisant des appels API Windows. Ils sont pour MASM plutôt que pour NASM, mais regardez-les. Vous pouvez trouver plus de détails dans cet "article 151950920".
;---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
pour les assembler et les lier en utilisant MASM, utilisez ceci pour les exécutables 32 bits:
ml.exe [filename] /link /subsystem:windows
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main
ou ceci pour l'exécutable 64 bits:
ml64.exe [filename] /link /subsystem:windows
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main
assembleur à plat n'a pas besoin d'un revêtement supplémentaire. Cela rend la programmation assembleur assez facile. Il est également disponible pour Linux.
C'est hello.asm
des exemples de Fasm:
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 crée un exécutable:
>fasm hello.asm flat assembler version 1.70.03 (1048575 kilobytes memory) 4 passes, 1536 bytes.
et c'est le programme dans IDA :
vous pouvez voir les trois appels: GetCommandLine
, MessageBox
et ExitProcess
.
pour obtenir un .exe avec le compilateur de NASM et le linker de Visual Studio ce code fonctionne très bien:
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
si ce code est sauvegardé sur par exemple" test64.asm", puis compiler:
nasm -f win64 test64.asm
produit" test 64.obj" Ensuite, pour faire le lien à partir de l'invite de commande:
path_to_link\link.exe test64.obj /subsystem:windows /entry:WinMain /libpath:path_to_libs /nodefaultlib kernel32.lib user32.lib /largeaddressaware:no
où path_to_link pourrait être C:\Program fichiers (x86)\Microsoft Visual Studio 10.0\VC\bin ou ailleurs votre lien.programme exe dans votre machine, path_to_libs pourrait être C:\Program fichiers (x86)\Kits Windows\8.1\Lib\winv6.3\um\x64 ou n'importe où sont vos bibliothèques (dans ce cas les deux kernel32.lib et user32.lib sont sur le même endroit, sinon utilisez une option pour chaque chemin dont vous avez besoin) et le /largeaddressaware:pas d'option est nécessaire pour éviter la plainte de linker sur les adresses à long (pour user32.lib dans ce cas). Aussi, comme il est fait ici, si le linker de Visual est invoqué à partir de l'invite de commande, il est nécessaire de configurer l'environnement au préalable (exécuter une fois vcvarsall.bat et / ou voir MS C++ 2010 et mspdb100.dll ).
sauf si vous appelez une fonction ce n'est pas du tout trivial. (Et, sérieusement, il n'y a pas de réelle différence dans la complexité entre appeler printf et appeler une fonction api win32.)
même DOS int 21h est vraiment juste un appel de fonction, même si c'est une API différente.
Si vous voulez le faire sans aide, vous devez parler à votre matériel vidéo directement, probablement écrit bitmaps des lettres de "Hello world" dans un framebuffer. Même alors la carte vidéo fait le travail de traduire ces valeurs de mémoire en signaux VGA/DVI.
notez que, vraiment, aucun de ces trucs jusqu'au matériel n'est plus intéressant en ASM qu'en C. Un programme "hello world" se résume à un appel de fonction. Une chose agréable à propos de ASM est que vous pouvez utiliser n'importe quel ABI que vous voulez assez facile; vous avez juste besoin de savoir ce que L'ABI est.
si vous voulez utiliser le linker de NASM et Visual Studio (link.exe) avec L'exemple Hello World D'anderstornvig, vous devrez créer un lien manuel avec la bibliothèque C Runtime qui contient la fonction printf ().
nasm -fwin32 helloworld.asm
link.exe helloworld.obj libcmt.lib
J'espère que ça aidera quelqu'un.
les meilleurs exemples sont ceux avec fasm, parce que fasm n'utilise pas de linker, qui cache la complexité de la programmation de fenêtres par une autre couche opaque de complexité. Si vous êtes satisfait d'un programme qui écrit dans une fenêtre gui, alors il y a un exemple pour cela dans le répertoire example de fasm.
si vous voulez un programme de console, qui permet une redirection de standard in et standard out qui est également possible. Il y a un programme d'exemple (helas highly non-trivial) disponible qui n'utilise pas d'interface graphique, et fonctionne strictement avec la console, qui est fasm lui-même. Cela peut être réduite à l'essentiel. (J'ai écrit un quatrième compilateur qui est un autre exemple non-gui, mais il est aussi non-trivial).
un tel programme a la commande suivante pour générer un en-tête exécutable approprié, normalement fait par un linker.
FORMAT PE CONSOLE
Une section appelée".idata ' contient une table qui aide windows pendant le démarrage à coupler les noms des fonctions vers les adresses d'exécution. Il contient également une référence au noyau.DLL qui est le système D'exploitation Windows.
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
le format de table est imposé par windows et contient des noms qui sont recherchés dans les fichiers système, lorsque le programme est lancé. Le FASM cache une partie des complexité derrière le mot-clé rva. Donc _ExitProcess@4 est une étiquette fasm et _exitProcess est une chaîne de caractères qui est cherchée par Windows.
votre programme est dans la section '.le texte". Si vous déclarer que section écriture lisible et exécutable, c'est la seule section, vous devez ajouter.
section '.text' code executable readable writable
Vous pouvez appeler toutes les installations que vous avez déclaré dans le .idata section. Pour un programme de console, vous avez besoin de _GetStdHandle pour trouver les scripteurs de fichiers standard in et standardout (en utilisant des noms symboliques comme STD_INPUT_HANDLE que fasm trouve dans le fichier include win32a).inc). Une fois que vous avez les descripteurs de fichier, vous pouvez faire WriteFile et ReadFile. Tout les fonctions sont décrites dans la documentation de kernel32. Vous êtes probablement au courant de cela ou vous n'essayeriez pas la programmation assembleur.
en résumé: il y a une table avec des noms asci qui s'apparient à l'OS de windows. Au démarrage, cela se transforme en une table d'adresses appelables, que vous utilisez dans votre programme.