Fetstil Fetstil Kursiv Understrykning linje färgläggning tabellverk Punktlista Nummerlista Vänster Centrerat högerställt Utfyllt Länk Bild htmlmode
  • Forum & Blog
    • Forum - översikt
      • .Net
        • asp.net generellt
        • c#
        • vb.net
        • f#
        • silverlight
        • microsoft surface
        • visual studio .net
      • databaser
        • sql-server
        • databaser
        • access
        • mysql
      • mjukvara klient
        • datorer och komponenter
        • nätverk, lan/wan
        • operativsystem
        • programvaror
        • säkerhet, inställningar
        • windows server
        • allmänt
        • crystal reports
        • exchange/outlook
        • microsoft office
      • mjukvara server
        • active directory
        • biztalk
        • exchange
        • linux
        • sharepoint
        • webbservers
        • sql server
      • appar (win/mobil)
      • programspråk
        • c++
        • delphi
        • java
        • quick basic
        • visual basic
      • scripting
        • asp 3.0
        • flash actionscript
        • html css
        • javascript
        • php
        • regular expresssion
        • xml
      • spel och grafik
        • DirectX
        • Spel och grafik
      • ledning
        • Arkitektur
        • Systemutveckling
        • krav och test
        • projektledning
        • ledningsfrågor
      • vb-sektioner
        • activeX
        • windows api
        • elektronik
        • internet
        • komponenter
        • nätverk
        • operativsystem
      • övriga forum
        • arbete karriär
        • erbjuda uppdrag och tjänster
        • juridiska frågor
        • köp och sälj
        • matematik och fysik
        • intern information
        • skrivklåda
        • webb-operatörer
    • Posta inlägg i forumet
    • Chatta med andra
  • Konto
    • Medlemssida
    • Byta lösenord
    • Bli bonsumedlem
    • iMail
  • Material
    • Tips & tricks
    • Artiklar
    • Programarkiv
  • JOBB
  • Student
    • Studentlicenser
  • KONTAKT
    • Om pellesoft
    • Grundare
    • Kontakta oss
    • Annonsering
    • Partners
    • Felanmälan
  • Logga in

Hem / Artiklar / Titel på artikeln

Introduktion till Assembly - Del 6: Procedurer och funktioner

Postad 2007-01-13 av Sebastian Andersson i sektionen ASP.NET, C#, Okategoriserat med 0 Kommentarer | Läst av: 6192, Betyg: 0%

Förord

Med MASM kan du skapa procedurer och funktioner, och det är det vi nu ska gå igenom. Jag kommer förklara hur procedurer och funktioner fungerar, hur man anropar de, hur de skapas, osv, men också gå in lite på djupet för de som är intresserade. Jag kommer också ta upp lokala variabler enär de relaterar till huvudämnena.
Innehåll
  » Förord
  » Procedurer och funktioner
  » Lokala variabler
Relaterade artiklar
  » Introduktion till Assembly
  » Introduktion till Assembly - Del 2: Instruktioner
  » Introduktion till Assembly - Del 3: Hello World!
  » Introduktion till Assembly - Del 4: Stacken
  » Introduktion till Assembly - Del 5: Globala variabler


Förord

Innan vi börjar tänker jag snabbt gå igenom vad en procedur resp. funktion är för de som inte känner till begreppen. En procedur, i data-termer, är ett stycke kod som gör någonting och sedan returnerar till programplatsen man var på innan proceduren anropades. Så du befinner dig på platsen D i programmet och anropar funktionen X som sedan gör någonting och när den är klar hoppar den tillbaka till D och fortsätter programflödet som vanligt. En funktion är nästan detsamma som en procedur, den väsentliga skillnaden är att den kan returnera ett värde som anroparen sedan kan läsa, något som procedurer inte gör. Om du programmerar i C eller VB så kommer du känna igen procedurer i assembly då de motsvarar nyckelorden "Sub" i VB och "void" i C.


Procedurer och funktioner

Vi börjar med att titta på syntaxen för hur man skapar procedurer och funktioner i MASM.

min_funktion_eller_procedur proc
; kroppen för funktionen eller proceduren
min_funktion_eller_procedur endp

Så du skriver alltså namnet på funktionen eller proceduren först och sedan nyckelordet "proc", kort för procedure, därefter koden och sist namnet igen tillsammans med nyckelordet "endp", kort för end procedure, men du kan givetvis skriva de i vilken ordning du vill när du väl har blivit bekant med syntaxen. Till skillnad från diverse högnivåspråk så finns det inget speciellt nyckelord för att deklarera funktioner, utan man går tillväga på samma sätt som procedurer och returnerar ett värde i registret EAX om man nu skriver en funktion och ett returvärde önskas. Nedan följer två exempel.

; Exempel: skapa en procedur som inte gör någonting
test_procedur proc
nop
ret
test_procedur endp

NOP, kort för no operation, är en instruktion som precis som namnet antyder; inte gör någonting. RET, kort för return, är en instruktion som returnerar till det tidigare programflödet innan funktionen eller proceduren anropades.

; Exempel: skapa en funktion som returnerar värdet 1
test_funktion proc
mov eax,1 ; flytta värdet 1 till EAX
ret
test_funktion endp

Regel: EAX är registret som används för att returnera värden i när man skriver funktioner, både i assembly och högnivåspråk.

Nu vet du hur man skapar funktioner och procedurer i assembly! Det finns två viktiga saker att komma ihåg som nybörjare: Du måste specifiera namnet på funktionen eller proceduren när du avslutar den, dvs "min_funktion_eller_procedur endp" alltså inte bara "endp", annars kommer du få ett assemblerfel som kan vara jobbiga att hitta om man har många assemblerfel, och du måste ALLTID specifiera instruktionen RET innan du avslutar funktionen eller proceduren med "endp", annars kommer programflödet fortsätta på fel plats och du kommer få tokiga fel eller en programkrasch

Säg det inte, jag vet vad du tänker! Ja, hur specifierar man parametrar i procedurer eller funktioner? Enkelt. Du specifierar parametrarna efter nyckelordet "proc". Nedan följer ett exempel.

; Exempel: skapa funktion med två argument
test_funktion_parametrar proc parameter1:DWORD,parameter2:DWORD
mov eax,parameter1
mov ecx,parameter2
add eax,ecx
ret
test_funktion_parametrar endp

Koden ovan tar värdet specifierat i parameter1 och adderar det med värdet specifierat i parameter2, returvärdet finns i EAX.

Du har oftast bara behov av parametrar av datatyperna BYTE, WORD och DWORD, men andra datatyper finns. Se "masm32.hlp" i masm32-projektet för en komplett lista.

Nedan följer en användbar funktion jag har skrivit för att demonstrera hur parametrar kan användas i assembly.

; Exempel: skapa en funktion och anropa den
pellesoft_strlen PROTO :DWORD ; en prototyp för vår funktion

.data

gszText db "testar att skapa en funktion och anropa den i assembly",0

.code

invoke pellesoft_strlen,addr gszText ; anropa pellesoft_strlen() och specifiera adressen till gszText som parameter
; EAX innehåller nu längden av strängen gszText
; ...

; vår egna strlen()/lstrlen() funktion
pellesoft_strlen proc lpString:DWORD
mov eax,lpString ; spara pekaren i EAX
dec eax

; en s k "unrolled-loop", kollar 4 bytes åt gången
@check_bytes:
inc eax ; öka och kolla nästa byte
cmp byte ptr [eax],0
jz @end
inc eax ; öka och kolla nästa byte
cmp byte ptr [eax],0
jz @end
inc eax ; öka och kolla nästa byte
cmp byte ptr [eax],0
jz @end
inc eax ; öka och kolla nästa byte
cmp byte ptr [eax],0
jnz @check_bytes
@end:
sub eax,lpString ; substrahera minnesadresserna för att få stränglängden
ret
pellesoft_strlen endp

Notera att du gärna får använda pellesoft_strlen() i dina egna assembly- eller högnivåspråksprojekt om du så önskar, men det vore uppskattande om du inkluderade en referens till min artikelserie eller mitt namn.;)

Jag tänker lite snabbt gå igenom procedurer och funktioner "under ytan", så att säga, men om du inte har hängt med i de tidigare artiklarna eller riktigt förstått assembly ännu så skulle jag rekommendera att du gick vidare till lokala variabler och kom tillbaka någongång senare när du har förkovrat dig lite.

Om du har en s k "disassembler" till hands, dvs ett program som översätter en binär programfil till maskinkod, så kan du kolla hur procedurer och funktioner egentligen ser ut. Funktioner och procedurer översätts egentligen bara till en "label" i assembler, som befinner sig på en konstant adress. Nedan ser du ett exempel på hur "disassemblad" (ursäkta svengelskan) kod ser ut.

00401244 fn_00401244:
00401244 55 push ebp
00401245 8BEC mov ebp,esp
00401247 6880000000 push 80h
0040124C FF7508 push dword ptr [ebp+8]
0040124F 6A00 push 0
00401251 E81C000000 call fn_00401272

De första siffrorna till vänster kallas för en relativa adress, eller RVA, och är egentligen bara en "offset" som är relativ med vart i minnet programfilen laddades av operativsystemet, och i mitten har du de hextalen som representerar instruktionerna till höger ("push ebp" blir alltså översatt till 0x55 av assemblern). De intressanta instruktionerna i koden ovan är de två första som befinner sig på 00401244 och 00401245. Vad dessa gör kallas för en "stack frame", och är egentligen bara ett enkelt och standardiserat sätt att initiera procedurer och funktioner på. Först reserveras EBP och sedan flyttas ESP (stack pekaren) till EBP och efter det kan du börja manipulera stacken, dvs allokera data osv. Vid funktionens slut kan du sedan se hur man återställer stacken och avslutar återvänder till returadressen...

00401268 C9 leave
00401269 C20400 ret 4

LEAVE är en instruktion som återställer stacken genom att flytta ESP (stack pekaren) som vid funktionen- eller procedurens start reserverades till EBP och POP:ar sedan EBP. Därefter hoppar vi tillbaka till den ursprungliga platsen genom RET.

Även trots en s k "stack frame" är ett standardiserat sätt att initiera procedurer och funktioner med, så behövs den egentligen inte. Det finns ofta en inställning i optimeringssektionen av ex. C-kompilerare som inaktiverar skapandet av s k "stack frames", och det är även möjligt i assembler. Du sparar ett par klockor om du väljer att inte skapa stack-frames, därför räknas det som en mindre optimering. Nedan har vi pellesoft_strlen() fast utan en "stack-frame".

; vår egna strlen()/lstrlen() funktion, med mindre optimeringar tillämpade
OPTION PROLOGUE:NONE ; inaktivera skapandet av
OPTION EPILOGUE:NONE ; en stack-frame

pellesoft_strlen proc lpString:DWORD
mov eax,[esp+1*4] ; lpString (esp+4)
sub eax,1

; en s k "unrolled-loop" som kollar 4 bytes åt gången
@check_bytes:
add eax,1 ; öka och kolla nästa byte
cmp byte ptr [eax],0
jz @end
add eax,1 ; öka och kolla nästa byte
cmp byte ptr [eax],0
jz @end
add eax,1 ; öka och kolla nästa byte
cmp byte ptr [eax],0
jz @end
add eax,1 ; öka och kolla nästa byte
cmp byte ptr [eax],0
jnz @check_bytes
@end:
sub eax,[esp+1*4] ; substrahera minnesadresserna för att få stränglängden
ret 4
pellesoft_strlen endp

OPTION PROLOGUE:PROLOGUEDEF ; återställ inställningen för
OPTION EPILOGUE:EPILOGUEDEF ; stack-frame

Att inaktivera "stack-frames" är bra i synnerhet för funktioner där du inte skapar lokala variabler eller på något sätt allokerar utrymme i stacken. Notera att om du inaktiverar skapandet av "stack-frames" i assembler så måste du allokera utrymme för dina lokala variabler själv och alltid hålla ett öga på stack-pekaren vilket kan vara jobbigt och svårt för nybörjare.


Lokala variabler

Att lära sig att deklarera lokala variabler är väldigt enkelt, även om du inte har hängt med i de tidigare artiklarna. De är egentligen bara utrymme allokerad på stacken, både i assembly och högnivåspråk så som C. I MASM deklarerar du en lokal variabel med nyckelordet LOCAL, och följer syntaxen nedan.

LOCAL variabel_namn:data_typ

Nedan följer ett par exempel på hur man deklarerar lokala variabler av olika datatyper.

; Exempel: deklarera lokala variabler
test_procedur proc
LOCAL byte_id:BYTE ; kan hålla en BYTE
LOCAL buf[255]:BYTE ; kan hålla 255 bytes
LOCAL num0:WORD ; kan hålla ett 16-bitars värde
LOCAL num1:DWORD ; kan hålla ett 32-bitars värde

mov byte_id,'A'
mov buf[128],'B'
mov num0,16000
mov eax,3240000
add eax,dword ptr [num0]
mov num1,eax
; ...
ret
test_procedur endp

Nedan finner du ett fullständigt exempel där vi använder oss av pellesoft_strlen() tillsammans med konsolen.


; Exempel: konsolapplikation och demonstration av pellesoft_strlen()
include \masm32\include\masm32rt.inc

pellesoft_strlen PROTO :DWORD

.code

start:

call main
inkey
exit

; vår egna strlen()/lstrlen() funktion, med mindre optimeringar tillämpade
OPTION PROLOGUE:NONE ; inaktivera skapandet av
OPTION EPILOGUE:NONE ; en stack-frame

pellesoft_strlen proc lpString:DWORD
mov eax,[esp+1*4] ; lpString (esp+4)
sub eax,1

; en s k "unrolled-loop" som kollar 4 bytes åt gången
@check_bytes:
add eax,1 ; öka och kolla nästa byte
cmp byte ptr [eax],0
jz @end
add eax,1 ; öka och kolla nästa byte
cmp byte ptr [eax],0
jz @end
add eax,1 ; öka och kolla nästa byte
cmp byte ptr [eax],0
jz @end
add eax,1 ; öka och kolla nästa byte
cmp byte ptr [eax],0
jnz @check_bytes
@end:
sub eax,[esp+1*4] ; substrahera minnesadresserna för att få stränglängden
ret 4
pellesoft_strlen endp

OPTION PROLOGUE:PROLOGUEDEF ; återställ inställningen för
OPTION EPILOGUE:EPILOGUEDEF ; stack-frame

main proc
LOCAL lpData:DWORD

mov lpData,input("Mata in ditt namn: ") ; lpData håller pekaren till texten vid retur av input()
invoke pellesoft_strlen,lpData
push eax ; reservera EAX eftersom den förstörs av "print"-makron nedan
print "Ditt namn är "
pop eax ; återhämta EAX
print ustr$(eax)," bokstäver långt",0dh,0ah ; CRLF ; skriv ut längden av namnet
ret
main endp

end start

Du finner det fullständiga programmet ovan med tillhörande källkod här.

Så enkelt är det!;) Och det var det för denna gången! Jag hoppas du har förstått det mesta av vad som har dryftats i artikeln, i annat fall, kommentera gärna och ställ frågor som jag möjligen kan lägga till i artikeln eller svara på i kommentar-sektionen. Ha en trevlig dag!
Upp

0 Kommentarer

Skriv en kommentar på artikeln

Ditt betyg på artikeln



Kommentar:





Nyligen

  • 09:09 Vill du köpa medicinska tester?
  • 12:47 Vem beviljar assistansen – kommune
  • 14:17 Någon med erfarenhet av hemstädnin
  • 14:14 Bör man använda sig av en båtförme
  • 14:12 Finns det någon intressant hundblo
  • 14:25 Tips på verktyg för att skapa QR-k
  • 14:23 Tips på verktyg för att skapa QR-k
  • 20:52 Fungerer innskuddsbonuser egentlig

Sidor

  • Hem
  • Bli bonusmedlem
  • Läs artiklar
  • Chatta med andra
  • Sök och erbjud jobb
  • Kontakta oss
  • Studentlicenser
  • Skriv en artikel

Statistik

Antal besökare:
Antal medlemmar:
Antal inlägg:
Online:
På chatten:
4 569 159
27 952
271 704
1 009
0

Kontakta oss

Frågor runt konsultation, rådgivning, uppdrag, rekrytering, annonsering och övriga ärenden. Ring: 0730-88 22 24 | pelle@pellesoft.se

© 1986-2013 PelleSoft AB. Last Build 4.1.7169.18070 (2019-08-18 10:02:21) 4.0.30319.42000
  • Om
  • Kontakta
  • Regler
  • Cookies