Assembly-kieli ja x86-tason järjestelmäohjelmointi · Oppitunti

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.

Oppitunti 2/412 vaihetta

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äskyn call print_hello.
  • Käskyn mov eax, 1 osoite (se on heti käskyn call print_hello jälkeen) työnnettiin pinoon.
  • Suoritin hyppäsi print_hello-proseduuriin.
  • print_hello suoritti viestin tulostamiseen tarvittavat käskyt.
  • ret poisti tallennetun paluuosoitteen pinosta ja hyppäsi takaisin _start-rutiiniin.
  • _start suoritti 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, N

Tä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- ja RBP-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 ebp ja mov ebp, esp sekä paikallisten muuttujien varaamisen käskyllä sub esp, N.
  • Pinokehys puretaan LEAVE-käskyllä (tai manuaalisesti käskyillä mov esp, ebp ja pop ebp) ennen RET-käskyä.

Seuraavaksi jatkamme opettelemalla, miten argumentteja välitetään proseduurille ja miten paluuarvoja haetaan.

Aloita maksutta

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

  1. Kutsupinon perusteet
  2. Proseduurien määrittäminen ja kutsuminen
  3. Argumenttien ja paluuarvojen välittäminen
  4. Pino­kehykset ja paikalliset muuttujat
← Takaisin: Assembly-kieli ja x86-tason järjestelmäohjelmointi