Introduktion till Assembly - Del 3: Hello World!
Förord
I denna artikel tänker jag gå igenom ett "Hello World!"-program i assembly, kodrad för kodrad. Jag ser helst också att du har hängt med i de tidigare artiklarna och redan besitter lite grundkunskap i assembly.OK, vi kör omedelbart i gång med koden! Jag tänker gå igenom varje rad och ge en så kortfattad och informativ beskrivning jag kan. (Du bör ha installerat MASM vid det här laget och även uppdaterat dina PATH/LIB/INCLUDE miljövariabler så att assemblern och länkaren hittar filerna de behöver)
.486
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.data
gszText db "Hello World!",0
.code
start:
invoke MessageBox,0,addr gszText,addr gszText,MB_OK
invoke ExitProcess,0
end start
OK, vi börjar med den första raden:
.486
Du kan tala om för assemblern vad för CPU-modell ditt program minst avser att stödja och vad för processorarkitekturer du vill dra nytta av. Numret 486 är kort för 80486, som är en 32-bitars CPU-modell utvecklad av Intel. Andra acceptabla nummer är bl a 386 (80386), 586 (I586) och 686 (I686). De senare (586 och 686) är oftast bara nödvändiga om du ex. vill ta del av SSE(2/3) instruktioner.
.model flat,stdcall
Detta talar om för assemblern att du vill använda dig av 32-bitars minnesmodellen (använd alltid detta i assembly-program som du avser att utveckla för 32-bitars miljöer).
option casemap:none
Detta ser till att verbalkänsligheten ställs på, vilket för övrigt är nödvändigt för att "Hello World"-programmet ska assemblas (huvudfilen windows.inc kräver det).
De övriga "include" kodraderna är ganska uppenbara, de inkluderar en huvudfil i källkoden, ungefär som nedanstående kod i C...
...eller möjligen också exempelvis som nedanstående kod i VB.NET (fast i .NET är det klasser snarare än råa API-funktioner)...
De övriga kodraderna är relaterade till länkarn som behöver veta vilka biblioteksfiler API-funktionerna programmet använder sig av befinner sig i.
.data
Denna kodraden talar om för assemblern att "här börjar data-sektionen" och då kommer allt du skriver nedan hamna i data-sektionen. Alltså ska du placera initierad data i .data sektionen. Oinitierad data bör placeras i en sektion som heter ".data?"
gszText är meddelandet vi vill visa, alltså en rad bokstäver efter varandra. Notera nollan på slutet, det är en s k strängavslutare och menar egentligen bara att "här slutar strängen i minnet".
.code
Detta talar om för assemblern att "här börjar kod-sektionen". Placera all din kod här.
start:
Detta är en s k "label" som visar vart programmet startar om man varken utvecklar ett konsolprogram (som förväntar en main-funktion) eller ett program med ett användargränssnitt så som ett fönster (som oftast förväntar en WinMain-funktion), med andra ord "entry-pointen". Du kan egentligen kalla den vad du vill, men se bara till att den stämmer överens med vad du specifierar i slutet av koden.
De båda invoke kodraderna är intressanta och en guldklippa i MASM, enligt många... De anropar funktionen du specifierar, fast på ett mer högnivå-liknande sätt. Samma kod hade kunnat skrivas i C...
...eller VB...
Ser du likheterna? invoke är en s k makro som sparar dig tid och möjligen huvudvärk då du inte behöver besvära dig med att PUSH:a alla parametrar på stacken själv, dvs så här...
push MB_OK
push offset gszText
push offset gszText
push 0
call MessageBoxA
Den sista kodraden i exemplet indikerar att programflödet avslutas där. Observera att den INTE avslutar programmet, det använder du API-funktionen ExitProcess för.
För att bygga programmet behöver du använda dig av konsolen eller något IDE som kan bygga assembly-program. Själv brukar jag skapa en s k batchfil (en textfil med filändelsen ”bat”). För att bygga det ovanstående ”Hello World”-programmet behöver du således skapa en fil med följande text och spara den som ex. make.bat.
@echo off
ml /c /coff hello.asm
link /SUBSYSTEM:WINDOWS hello.obj
pause
Egentligen behöver du inte “pause”, men den kan vara bra i fall något skulle gå snett under processen och du vill ta din tid och läsa felen som uppstod.
Du finner det kompletta "Hello World!"-programmet här.
I nästa artikel kommer vi gå igenom en viktig del av assembly: stacken. Missa inte det!
Hello World!
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.data
gszText db "Hello World!",0
.code
start:
invoke MessageBox,0,addr gszText,addr gszText,MB_OK
invoke ExitProcess,0
end start
OK, vi börjar med den första raden:
Du kan tala om för assemblern vad för CPU-modell ditt program minst avser att stödja och vad för processorarkitekturer du vill dra nytta av. Numret 486 är kort för 80486, som är en 32-bitars CPU-modell utvecklad av Intel. Andra acceptabla nummer är bl a 386 (80386), 586 (I586) och 686 (I686). De senare (586 och 686) är oftast bara nödvändiga om du ex. vill ta del av SSE(2/3) instruktioner.
Detta talar om för assemblern att du vill använda dig av 32-bitars minnesmodellen (använd alltid detta i assembly-program som du avser att utveckla för 32-bitars miljöer).
Detta ser till att verbalkänsligheten ställs på, vilket för övrigt är nödvändigt för att "Hello World"-programmet ska assemblas (huvudfilen windows.inc kräver det).
De övriga "include" kodraderna är ganska uppenbara, de inkluderar en huvudfil i källkoden, ungefär som nedanstående kod i C...
#include
...eller möjligen också exempelvis som nedanstående kod i VB.NET (fast i .NET är det klasser snarare än råa API-funktioner)...
Imports System.Net.Sockets
De övriga kodraderna är relaterade till länkarn som behöver veta vilka biblioteksfiler API-funktionerna programmet använder sig av befinner sig i.
Denna kodraden talar om för assemblern att "här börjar data-sektionen" och då kommer allt du skriver nedan hamna i data-sektionen. Alltså ska du placera initierad data i .data sektionen. Oinitierad data bör placeras i en sektion som heter ".data?"
gszText är meddelandet vi vill visa, alltså en rad bokstäver efter varandra. Notera nollan på slutet, det är en s k strängavslutare och menar egentligen bara att "här slutar strängen i minnet".
Detta talar om för assemblern att "här börjar kod-sektionen". Placera all din kod här.
Detta är en s k "label" som visar vart programmet startar om man varken utvecklar ett konsolprogram (som förväntar en main-funktion) eller ett program med ett användargränssnitt så som ett fönster (som oftast förväntar en WinMain-funktion), med andra ord "entry-pointen". Du kan egentligen kalla den vad du vill, men se bara till att den stämmer överens med vad du specifierar i slutet av koden.
De båda invoke kodraderna är intressanta och en guldklippa i MASM, enligt många... De anropar funktionen du specifierar, fast på ett mer högnivå-liknande sätt. Samma kod hade kunnat skrivas i C...
const char *pszText="Hello World!";
MessageBox(NULL,pszText,pszText,MB_OK);
...eller VB...
MessageBox 0, "Hello World!", "Hello World!", MB_OK ' (eller MsgBox)
Ser du likheterna? invoke är en s k makro som sparar dig tid och möjligen huvudvärk då du inte behöver besvära dig med att PUSH:a alla parametrar på stacken själv, dvs så här...
push offset gszText
push offset gszText
push 0
call MessageBoxA
Den sista kodraden i exemplet indikerar att programflödet avslutas där. Observera att den INTE avslutar programmet, det använder du API-funktionen ExitProcess för.
För att bygga programmet behöver du använda dig av konsolen eller något IDE som kan bygga assembly-program. Själv brukar jag skapa en s k batchfil (en textfil med filändelsen ”bat”). För att bygga det ovanstående ”Hello World”-programmet behöver du således skapa en fil med följande text och spara den som ex. make.bat.
ml /c /coff hello.asm
link /SUBSYSTEM:WINDOWS hello.obj
pause
Egentligen behöver du inte “pause”, men den kan vara bra i fall något skulle gå snett under processen och du vill ta din tid och läsa felen som uppstod.
Du finner det kompletta "Hello World!"-programmet här.
I nästa artikel kommer vi gå igenom en viktig del av assembly: stacken. Missa inte det!
0 Kommentarer