Assembly-sprog og x86-systemprogrammering på lavt niveau · Lektion

Definition og kald af procedurer

Lær at definere Deres egne procedurer (funktioner) ved hjælp af CALL- og RET-instruktioner, og forstå opsætning af stack frames.

Lektion 2 af 412 trin

Definition og kald af procedurer er en gratis Assembly-sprog og x86-systemprogrammering på lavt niveau-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Assembly-sprog og x86-systemprogrammering på lavt niveau, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Assembly-sprog og x86-systemprogrammering på lavt niveau-kurset indeholder 4 lektioner i alt.

Hvad er procedurer?

I assembly er en procedure (ofte kaldet en funktion eller et underprogram) en kodeblok, der er designet til at udføre en bestemt opgave. Procedurer hjælper med at organisere programmet og undgå gentagelse af kode.

Tænk på dem som funktioner i programmeringssprog på højt niveau som C++ eller Python. De gør det muligt at opdele komplekse problemer i mindre, håndterbare dele, så koden bliver modulær og lettere at læse.

Kald af en procedure med CALL

Du udfører en procedure ved hjælp af instruktionen CALL. Når CALL udføres, sker der to vigtige ting:

  • Adressen på instruktionen lige efter CALL pushes på stakken. Den kaldes returadressen.
  • CPU'en springer derefter til startadressen for den angivne procedure.

Denne mekanisme sikrer, at programmet ved præcis, hvor udførelsen skal genoptages, når proceduren er færdig med sit arbejde.

Returnering fra en procedure med RET

Når en procedure er færdig med sin opgave, skal den give kontrollen tilbage til den kode, der kaldte den. Det opnås ved hjælp af instruktionen RET.

Når RET udføres:

  • popper CPU'en returadressen fra toppen af stakken.
  • CPU'en springer derefter til den hentede adresse, så udførelsen genoptages ved instruktionen lige efter det oprindelige CALL.

Tilsammen udgør CALL og RET det grundlæggende par til håndtering af programflowet mellem forskellige procedurer.

Dit første procedurekald

Lad os se på et enkelt assembly-program, der demonstrerer et grundlæggende procedurekald og en returnering. Vi definerer en procedure med navnet print_hello og kalder den fra programmets startpunkt, _start.

Dette eksempel bruger Linux-systemkald til output og afslutning af programmet.

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

Forstå outputtet

Når du kører den foregående kode, udskriver den "Hello from proc!" i din konsol. Her er en trinvis gennemgang af, hvad der skete:

  • Rutinen _start udførte call print_hello.
  • Adressen på instruktionen mov eax, 1 (som står lige efter call print_hello) blev pushed på stakken.
  • CPU'en sprang til proceduren print_hello.
  • print_hello udførte sine instruktioner for at udskrive meddelelsen.
  • ret poppede den gemte returadresse fra stakken og sprang tilbage til rutinen _start.
  • _start udførte derefter systemkaldet for at afslutte programmet.

Hvad er stakrammer?

Når der kaldes på en procedure, har den ofte brug for sit eget private arbejdsområde på stakken til håndtering af sine data. Dette dedikerede område på stakken kaldes en stakramme.

En stakramme indeholder typisk flere vigtige oplysninger for en procedure:

  • Returadressen (pushed af instruktionen CALL).
  • Gemte registerværdier (f.eks. den kaldende funktions basispeger).
  • Lokale variable, der er specifikke for proceduren.
  • Argumenter, der sendes til proceduren (det gennemgår vi i næste lektion!).

Opsætning af basispegeren (EBP)

Registret basispeger (`EBP` i 32-bit, `RBP` i 64-bit) er et vigtigt værktøj til håndtering af stakrammer. Det giver et stabilt referencepunkt i den aktuelle stakramme, så det bliver nemt at få adgang til lokale variable og argumenter.

En almindelig opsætningssekvens helt i begyndelsen af en procedure er:

  • push ebp: Dette gemmer den kaldende funktions aktuelle `EBP`-værdi på stakken, så den kan gendannes senere.
  • mov ebp, esp: Dette indstiller `EBP` til stakpegerens aktuelle værdi (`ESP`) og fastlægger dermed basis for den nye stakramme.

Allokering af lokale variable

Efter opsætning af `EBP` kan en procedure allokere plads til sine egne lokale variable på stakken. Det gøres typisk ved blot at dekrementere stakpegeren (`ESP`).

sub esp, N

Her repræsenterer `N` det samlede antal byte, der kræves til alle lokale variable. For eksempel allokerer sub esp, 4 nok plads til ét 32-bit-heltal.

Der kan derefter opnås effektiv adgang til disse lokale variable relativt til `EBP` (f.eks. [ebp-4], [ebp-8] osv.).

Nedtagning af stakrammen

Før en procedure returnerer, skal dens stakramme nedtages korrekt, så stakken gendannes til sin oprindelige tilstand. Det indebærer at frigive lokale variable og gendanne den kaldende funktions basispeger.

Instruktionen LEAVE er en praktisk måde at udføre disse to handlinger i ét trin:

  • mov esp, ebp: Dette frigiver eventuelle lokale variable ved at flytte `ESP` tilbage til det sted, som `EBP` peger på (rammens basis).
  • pop ebp: Dette gendanner den kaldende funktions `EBP`-værdi, som blev gemt i begyndelsen af proceduren.

Efter LEAVE er stakken placeret korrekt, så instruktionen RET kan poppe returadressen.

Procedure med en stakramme

Dette eksempel demonstrerer en komplet procedure, der opsætter en korrekt stakramme, allokerer plads til en hypotetisk lokal variabel og derefter nedtager rammen korrekt før returnering.

Bemærk, hvordan `push ebp`, `mov ebp, esp`, `sub esp, 4`, `leave` og `ret` arbejder sammen.

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

Kontrol af procedurekaldets flow

Se på følgende x86-assembly-kodestykke:

  call my_function
  mov eax, 1
my_function:
  ret

Hvilken specifik adresse pushes på stakken af instruktionen call my_function?

Opsamling: Definition og kald af procedurer

Vi har gennemgået de vigtigste begreber inden for definition og kald af procedurer i x86-assembly. Her er de vigtigste pointer fra lektionen:

  • Instruktionen CALL pusher returadressen på stakken og overfører kontrollen til en procedure.
  • Instruktionen RET popper returadressen fra stakken og overfører kontrollen tilbage til den kaldende kode.
  • Stakrammer, som primært håndteres med registret EBP/RBP, giver et dedikeret og organiseret arbejdsområde på stakken til en procedures lokale variable og gemte registre.
  • En typisk opsætning af en stakramme omfatter push ebp, mov ebp, esp og allokering af lokale variable med sub esp, N.
  • Stakrammen tages ned med instruktionen LEAVE (eller manuelt med mov esp, ebp og pop ebp) før RET.

Derefter bygger vi videre på dette ved at lære, hvordan du sender argumenter til procedurer og henter returværdier.

Gratis at komme i gang

Lær Assembly med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
12
Lektioner
48

Ofte stillede spørgsmål

Er lektionen “Definition og kald af procedurer” gratis?

Ja — hele teksten til “Definition og kald af procedurer” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Assembly-sprog og x86-systemprogrammering på lavt niveau-kurset, skal du opgradere til CoddyKit PRO. Assembly-sprog og x86-systemprogrammering på lavt niveau-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Definition og kald af procedurer”?

Lær at definere Deres egne procedurer (funktioner) ved hjælp af CALL- og RET-instruktioner, og forstå opsætning af stack frames. Du øver dig i Assembly-sprog og x86-systemprogrammering på lavt niveau med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Assembly-sprog og x86-systemprogrammering på lavt niveau?

Der kræves ingen tidligere erfaring. Assembly-sprog og x86-systemprogrammering på lavt niveau på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.

Hvor lang tid tager lektionen “Definition og kald af procedurer”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Assembly-sprog og x86-systemprogrammering på lavt niveau-lektion?

Ja. Alle Assembly-sprog og x86-systemprogrammering på lavt niveau-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Grundprincipper i call stack
  2. Definition og kald af procedurer
  3. Videregivelse af argumenter og returværdier
  4. Stack frames og lokale variabler
← Tilbage til Assembly-sprog og x86-systemprogrammering på lavt niveau