Proseduurien määrittäminen ja kutsuminen
Opiskelkaa määrittämään omia proseduureja eli funktioita CALL- ja RET-käskyillä sekä ymmärtämään pinokehysten muodostaminen.
Proseduurien määrittäminen ja kutsuminen on ilmainen Assembly-kieli ja x86-tason järjestelmäohjelmointi-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Assembly-kieli ja x86-tason järjestelmäohjelmointi-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Assembly-kieli ja x86-tason järjestelmäohjelmointi-kurssilla on yhteensä 4 oppituntia.
Mitä proseduurit ovat?
Assemblyssä proseduuri (josta käytetään usein myös nimityksiä funktio tai aliohjelma) on tiettyä tehtävää varten suunniteltu koodilohko. Proseduurit auttavat jäsentämään ohjelmaa ja välttämään koodin toistamista.
Niitä voi ajatella korkean tason kielten, kuten C++:n tai Pythonin, funktioiden kaltaisina. Niiden avulla monimutkaiset ongelmat voidaan jakaa pienempiin ja hallittaviin osiin, jolloin koodista tulee modulaarisempaa ja helpommin luettavaa.
Proseduurin kutsuminen CALL-käskyllä
Proseduuri suoritetaan CALL-käskyllä. Kun CALL suoritetaan, tapahtuu kaksi tärkeää asiaa:
CALL-käskyä välittömästi seuraavan käskyn osoite työnnetään pinoon. Tätä kutsutaan paluuosoitteeksi.- Suoritin hyppää määrittämäsi proseduurin aloitusosoitteeseen.
Näin ohjelma tietää tarkalleen, mistä suoritusta jatketaan, kun proseduurin tehtävä on valmis.
Proseduurista palaaminen RET-käskyllä
Kun proseduurin tehtävä on valmis, sen on luovutettava suoritus takaisin proseduurin kutsuneelle koodille. Tämä tehdään RET-käskyllä.
Kun RET suoritetaan:
- Suoritin poistaa paluuosoitteen pinon huipulta.
- Sen jälkeen suoritin hyppää tähän poistettuun osoitteeseen ja jatkaa suoritusta alkuperäistä
CALL-käskyä välittömästi seuraavasta käskystä.
Yhdessä CALL ja RET muodostavat perusparin, jolla ohjelman suoritusvirtaa hallitaan eri proseduurien välillä.
Ensimmäinen proseduurikutsusi
Tarkastelemme yksinkertaista assembly-ohjelmaa, joka havainnollistaa proseduurin kutsumista ja siitä palaamista. Määrittelemme proseduurin nimeltä print_hello ja kutsumme sitä ohjelmamme aloituskohdasta _start.
Tässä esimerkissä tulostamiseen ja ohjelman lopettamiseen käytetään Linux-järjestelmäkutsuja.
section .data
msg db "Hello from proc!", 0xA
len equ $ - msg
section .text
global _start
_start:
call print_hello
; Exit program (sys_exit)
mov eax, 1 ; System call number for sys_exit
xor ebx, ebx ; Exit code 0
int 0x80
print_hello:
; Print "Hello from proc!" (sys_write)
mov eax, 4 ; System call number for sys_write
mov ebx, 1 ; File descriptor for stdout
mov ecx, msg ; Address of string to write
mov edx, len ; Length of string
int 0x80
ret
Tulosteen ymmärtäminen
Kun suoritat edellisen koodin, konsoliin tulostuu "Hello from proc!". Tapahtumat etenivät seuraavasti:
_start-rutiini suoritti käskyncall print_hello.- Käskyn
mov eax, 1osoite (se on heti käskyncall print_hellojälkeen) työnnettiin pinoon. - Suoritin hyppäsi
print_hello-proseduuriin. print_hellosuoritti viestin tulostamiseen tarvittavat käskyt.retpoisti tallennetun paluuosoitteen pinosta ja hyppäsi takaisin_start-rutiiniin._startsuoritti sitten järjestelmäkutsun ohjelman lopettamiseksi.
Mitä pinokehykset ovat?
Kun proseduuria kutsutaan, se tarvitsee usein pinosta oman yksityisen työtilan tietojensa hallintaan. Tätä pinon omaa aluetta kutsutaan pinokehykseksi.
Pinokehys sisältää yleensä useita proseduurin kannalta tärkeitä tietoja:
- Paluuosoite (
CALL-käskyn pinoon tallentama osoite). - Tallennetut rekisteriarvot (esimerkiksi kutsujan kehysosoitin).
- Proseduurikohtaiset paikalliset muuttujat.
- Proseduurille välitetyt argumentit (käsittelemme tämän seuraavassa oppitunnissa!).
Kehysosoittimen (EBP) määrittäminen
Base pointer -rekisteri (`EBP` 32-bittisessä ja `RBP` 64-bittisessä ympäristössä) on tärkeä työkalu pinokehysten hallintaan. Se tarjoaa vakaan viitepisteen nykyisen pinokehyksen sisällä ja helpottaa paikallisten muuttujien sekä argumenttien käsittelyä.
Proseduurin alussa käytetään usein seuraavaa alustussarjaa:
push ebp: Tämä tallentaa kutsujan nykyisen `EBP`-arvon pinoon, jotta se voidaan myöhemmin palauttaa.mov ebp, esp: Tämä asettaa `EBP`:n arvoksi pino-osoittimen nykyisen arvon (`ESP`) ja määrittää uuden pinokehyksen perustan.
Paikallisten muuttujien varaaminen
Kun `EBP` on alustettu, proseduurille voidaan varata pinosta tilaa sen omille paikallisille muuttujille. Tämä tehdään yleensä yksinkertaisesti pienentämällä pino-osoittimen (`ESP`) arvoa.
sub esp, NTässä `N` tarkoittaa kaikkien paikallisten muuttujien tarvitsemien tavujen kokonaismäärää. Esimerkiksi sub esp, 4 varaa tarpeeksi tilaa yhdelle 32-bittiselle kokonaisluvulle.
Paikallisiin muuttujiin voidaan tämän jälkeen päästä tehokkaasti käsiksi suhteessa `EBP`:hen (esimerkiksi [ebp-4], [ebp-8] ja niin edelleen).
Pinokehyksen purkaminen
Ennen proseduurista palaamista sen pinokehys on purettava asianmukaisesti, jotta pino palautuu alkuperäiseen tilaansa. Tähän kuuluu paikallisten muuttujien varaaman tilan vapauttaminen ja kutsujan kehysosoittimen palauttaminen.
LEAVE-käsky on kätevä tapa suorittaa nämä kaksi toimintoa yhdellä käskyllä:
mov esp, ebp: Tämä vapauttaa paikallisille muuttujille varatun tilan siirtämällä `ESP`:n takaisin kohtaan, johon `EBP` osoittaa (kehyksen alkuun).pop ebp: Tämä palauttaa proseduurin alussa tallennetun kutsujan `EBP`-arvon.
LEAVE-käskyn jälkeen pino on oikeassa tilassa, jotta RET-käsky voi poistaa paluuosoitteen.
Proseduuri pinokehyksen kanssa
Tässä esimerkissä esitellään kokonainen proseduuriohjelma, joka määrittää asianmukaisen pinokehyksen, varaa tilaa kuvitteelliselle paikalliselle muuttujalle ja purkaa kehyksen oikein ennen paluuta.
Huomaa, miten `push ebp`, `mov ebp, esp`, `sub esp, 4`, `leave` ja `ret` toimivat yhdessä.
section .data
msg db "Procedure with frame!", 0xA
len equ $ - msg
section .text
global _start
_start:
call my_framed_proc
; Exit program
mov eax, 1
xor ebx, ebx
int 0x80
my_framed_proc:
push ebp ; 1. Save caller's EBP
mov ebp, esp ; 2. Set EBP for new frame
sub esp, 4 ; 3. Allocate 4 bytes for a local variable
; mov dword [ebp-4], 123 ; Example: store a local value
; Print message (for demonstration)
mov eax, 4
mov ebx, 1
mov ecx, msg
mov edx, len
int 0x80
leave ; 4. Deallocate locals, restore EBP
ret ; 5. Return to caller
Proseduurikutsun kulun tarkistus
Tarkastele seuraavaa x86-assemblykatkelmaa:
call my_function
mov eax, 1
my_function:
ret
Mikä tietty osoite call my_function -käskyn yhteydessä työnnetään pinoon?
Kertaus: proseduurien määrittäminen ja kutsuminen
Olemme käsitelleet x86-assemblyn proseduurien määrittämisen ja kutsumisen keskeiset käsitteet. Tässä oppitunnin tärkeimmät asiat:
CALL-käsky työntää paluuosoitteen pinoon ja siirtää suorituksen proseduurille.RET-käsky poistaa paluuosoitteen pinosta ja siirtää suorituksen takaisin kutsujalle.- Ensisijaisesti
EBP- jaRBP-rekistereillä hallitut pinokehykset tarjoavat proseduurin paikallisille muuttujille ja tallennetuille rekistereille oman järjestelmällisen työtilan pinossa. - Tyypillinen pinokehyksen määritys sisältää käskyt
push ebpjamov ebp, espsekä paikallisten muuttujien varaamisen käskylläsub esp, N. - Pinokehys puretaan
LEAVE-käskyllä (tai manuaalisesti käskyillämov esp, ebpjapop ebp) ennenRET-käskyä.
Seuraavaksi jatkamme opettelemalla, miten argumentteja välitetään proseduurille ja miten paluuarvoja haetaan.
Opi Assembly tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 12
- Oppitunnit
- 48
Usein kysytyt kysymykset
Onko oppitunti ”Proseduurien määrittäminen ja kutsuminen” ilmainen?
Kyllä – oppitunnin ”Proseduurien määrittäminen ja kutsuminen” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Assembly-kieli ja x86-tason järjestelmäohjelmointi-kurssin, päivitä CoddyKit PROhon. Assembly-kieli ja x86-tason järjestelmäohjelmointi-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Proseduurien määrittäminen ja kutsuminen”?
Opiskelkaa määrittämään omia proseduureja eli funktioita CALL- ja RET-käskyillä sekä ymmärtämään pinokehysten muodostaminen. Harjoittelet Assembly-kieli ja x86-tason järjestelmäohjelmointi-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Assembly-kieli ja x86-tason järjestelmäohjelmointi-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Assembly-kieli ja x86-tason järjestelmäohjelmointi-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.
Kuinka kauan ”Proseduurien määrittäminen ja kutsuminen”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Assembly-kieli ja x86-tason järjestelmäohjelmointi-oppitunnilla?
Kyllä. Jokainen Assembly-kieli ja x86-tason järjestelmäohjelmointi-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Kutsupinon perusteet
- Proseduurien määrittäminen ja kutsuminen
- Argumenttien ja paluuarvojen välittäminen
- Pinokehykset ja paikalliset muuttujat