2009-06-21 7 views
64

Je voulais écrire quelque chose de basique dans l'assemblage sous Windows, j'utilise NASM, mais je ne peux rien faire fonctionner. Comment écrire et compiler hello world sans l'aide des fonctions C sur Windows?Comment écrire un hello world en assembleur sous Windows?

+0

Consultez aussi le kit de démarrage de Windows Gibson [Small Is Beautiful] de [http://www.grc.com/smgassembly.htm] de Steve Gibson. – Jeremy

+0

Ne pas utiliser c-libraries est une contrainte quelque peu étrange. Il faut appeler une bibliothèque dans le système d'exploitation MS-Windows. probablement kernel32.dll.Whether Microsoft a écrit ceci en c ou Pascal semble hors de propos. Cela signifie-t-il que seules les fonctions fournies par le système d'exploitation peuvent être appelées, qu'est-ce qui, dans un système de type Unix, s'appellerait des appels système? –

+0

Avec les bibliothèques C, je suppose qu'il ou elle veut dire sans utiliser de bibliothèques d'exécution C comme celles fournies avec GCC ou MSVC. Bien sûr, il ou elle devra utiliser certaines DLL Windows standard, comme kernel32.dll. –

Répondre

29

NASM examples.

; ---------------------------------------------------------------------------- 
; 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 

Lancez ensuite

nasm -fwin32 helloworld.asm 
gcc helloworld.obj 
a 

Il y a aussi The Clueless Newbies Guide to Hello World in Nasm sans l'utilisation d'une bibliothèque C. Alors le code ressemblerait à ceci.

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

Bonne chance.

+13

La question mentionne explicitement "sans utiliser les bibliothèques C" –

+0

Il n'y a pas de moyen fiable de faire cela sans appeler une fonction C à un moment donné. Sauf si par "fonction C" vous voulez dire "fonction C standard". –

+20

Incorrect. La bibliothèque C elle-même peut évidemment le faire, c'est donc possible. En fait, c'est un peu plus difficile. Vous avez juste besoin d'appeler WriteConsole() avec les 5 bons paramètres. – MSalters

104

Cet exemple montre comment accéder directement à l'API Windows et ne pas lier dans la bibliothèque standard C.

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: 

Pour compiler, vous aurez besoin MSNA et Link.exe (de Visual Studio Standard Edition)

 
    nasm -fwin32 hello.asm 
    link /subsystem:console /nodefaultlib /entry:main hello.obj 
+15

vous avez probablement besoin d'inclure le kernel32.lib pour lier ceci (je l'ai fait). lien/sous-système: console/nodefaultlib/entrée: main hello.obj kernel32.lib –

+4

Comment lier l'obj avec ld.exe de MinGW? – DarrenVortex

+3

@DarrenVortex 'gcc hello.obj' – towry

4

À moins que vous appelez une fonction ce n'est pas du tout trivial. (Et, sérieusement, il n'y a pas de réelle différence de complexité entre l'appel de printf et l'appel d'une fonction win32 api.)

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 directement à votre matériel vidéo, en écrivant probablement des 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, rien de tout cela jusqu'au hardware n'est plus intéressant dans ASM que dans C. Un programme "hello world" se résume à un appel de fonction. Une bonne chose à propos de l'ASM est que vous pouvez utiliser n'importe quel ABI que vous voulez assez facile; vous avez juste besoin de savoir ce que ABI est.

+0

Ceci est un excellent point --- ASM et C s'appuient tous les deux sur une fonction fournie par le système d'exploitation (_WriteFile dans Windows). Alors, où est la magie? C'est dans le code du pilote de périphérique pour la carte vidéo. –

+0

Ceci est complètement à côté du point. L'affiche demande un programme assembleur qui s'exécute "sous Windows". Cela signifie que les fonctionnalités Windows peuvent être utilisées (par exemple, kernel32.dll), mais pas d'autres fonctionnalités telles que libc sous Cygwin. Pour pleurer à haute voix, l'affiche dit explicitement pas de c-bibliothèques. –

15

Voici des exemples Win32 et Win64 utilisant des appels API Windows. Ils sont pour MASM plutôt que NASM, mais jetez un oeil à eux. Vous pouvez trouver plus de détails dans l'article this.

;---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 assembler et relier ces utilisant MASM, utiliser pour 32 bits exécutable:

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

ou cela pour exécutable 64 bits:

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

+1 pour votre réponse. Pouvez-vous ajouter le code d'assemblage pour Windows sur ARM (WOA)? – Annie

+0

Pourquoi rsp nécessite 0x28 octets et non 0x20? Toutes les références sur la convention d'appel disent qu'il devrait être de 32 mais il semble en exiger 40 en pratique. – douggard

+1

Répondu ici: https://stackoverflow.com/a/19128544/1176872 – douggard

4

Si vous voulez utiliser l'éditeur de liens NASM et Visual Studio (link.exe) avec l'exemple Hello World d'anderstornvig, vous devrez lier manuellement avec C Runtime Libary qui contient la fonction printf().

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

Espérons que cela aide quelqu'un.

12

Flat Assembler n'a pas besoin d'un éditeur de liens supplémentaire. Cela rend la programmation de l'assembleur assez facile. Il est également disponible pour Linux.

Ceci est hello.asm des exemples 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 fichier exécutable:

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

Et c'est le programme IDA:

enter image description here

Vous pouvez voir les trois cal ls: GetCommandLine, MessageBox et ExitProcess.

7

Pour obtenir un .exe avec NASM'compiler et éditeur de liens 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 enregistré sur par exemple "Test64.asm", puis de compiler:

nasm -f win64 test64.asm 

Produit "test64.obj" ensuite relier à 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 

path_to_link pourrait être C: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ VC \ bin ou n'importe où est votre programme link.exe dans votre ordinateur, path_to_libs peut être C: \ Program Files (x86) \ Windows Kits \ 8.1 \ Lib \ winv6. 3 \ um \ x64 ou où se trouvent vos bibliothèques (dans ce cas, kernel32.lib et user32.lib sont au même endroit, sinon utilisez une option pour chaque chemin dont vous avez besoin) et l'option /largeaddressaware: no est nécessaire pour éviter que l'éditeur de liens se plaigne d'adresses trop longues (pour user32.lib dans ce cas). En outre, comme cela est fait ici, si l'éditeur de liens de Visual est invoqué à partir de l'invite de commande, il est nécessaire de configurer l'environnement précédemment (exécuter une fois vcvarsall.bat et/ou voir MS C++ 2010 and mspdb100.dll).

2

Les meilleurs exemples sont ceux avec fasm, car fasm n'utilise pas de lieur, ce qui cache la complexité de la programmation de fenêtres par une autre couche de complexité opaque. Si vous êtes satisfait d'un programme qui écrit dans une fenêtre graphique, alors il y a un exemple dans le répertoire exemple de fasm.

Si vous voulez un programme de console, cela permet également la redirection de l'entrée standard et de la sortie standard. Il existe un exemple de programme (hélas non trivial) disponible qui n'utilise pas de gui et qui fonctionne strictement avec la console, c'est-à-dire fasm lui-même. Cela peut être réduit à l'essentiel. (J'ai écrit un quatrième compilateur qui est un autre exemple non-gui, mais il est également non-trivial).

Un tel programme a la commande suivante pour générer un en-tête exécutable approprié, normalement effectué par un éditeur de liens.

FORMAT PE CONSOLE 

Une section intitulée « .idata » contient une table qui aide les fenêtres au démarrage des noms de couple de fonctions aux adresses des runtimes.Il contient également une référence à KERNEL.DLL qui est le système d'exploitation Windows.

section '.idata' import data readable writeable 
... 

Votre programme se trouve dans la section '.text'. Si vous déclarez cette section accessible en écriture et exécutable, c'est la seule section dont vous avez besoin.

section '.text' code executable readable writable 

Vous pouvez appeler tous les services que vous avez déclarés dans la section .idata. Pour un programme de console, vous avez besoin de _GetStdHandle pour trouver les fichiers de filtrage pour 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 fichiers, vous pouvez écrire WriteFile et ReadFile. Toutes les fonctions sont décrites dans la documentation de kernel32. Vous êtes probablement au courant de cela ou vous n'essaieriez pas la programmation en assembleur.

En résumé: Il existe une table avec des noms asci qui se couplent au système d'exploitation Windows. Lors du démarrage, ceci est transformé en une table d'adresses appelables que vous utilisez dans votre programme.

Questions connexes