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

Assemblyn kutsuminen C:stä

Opiskelkaa integroimaan assembly-rutiineja C/C++-projekteihin, välittämään parametreja ja vastaanottamaan paluuarvoja kutsukäytäntöjen avulla.

Oppitunti 1/411 vaihetta

Assemblyn kutsuminen C:stä on ilmainen Assembly-kieli ja x86-tason järjestelmäohjelmointi-oppitunti CoddyKitissä. Tämä on oppitunti 1/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.

Miksi C tarvitsee assemblyä

Miksi C/C++- ja assembly-koodia yhdistettäisiin? Se saattaa vaikuttaa vanhanaikaiselta, mutta siihen on painavia syitä!

  • Suorituskyky: Kriittisissä koodiosissa käsin optimoitu assembly voi olla kääntäjän tuottamaa koodia nopeampaa.
  • Laitteiston käyttö: Voit käyttää suoraan laitteiston ominaisuuksia, joita C/C++ ei tarjoa.
  • Erityiskäskyt: Voit käyttää suoraan suorittimen erityiskäskyjä (esimerkiksi salaukseen tai multimediaan).
  • Vanha koodi: Voit integroida olemassa olevia assembly-rutiineja tai käyttöjärjestelmän komponentteja.

Näin saat "molempien parhaat puolet": C:n korkean tason rakenteen ja assemblyn matalan tason tehon.

Kutsusopimus

Kun C kutsuu assembly-funktiota, niiden on sovittava siitä, miten asiat toimivat. Tätä sopimusta kutsutaan kutsukäytännöksi.

Se määrittää:

  • Miten argumentit välitetään (rekistereissä vai pinossa).
  • Kuka siivoaa pinon kutsun jälkeen.
  • Mitkä rekisterit kutsutun funktion on säilytettävä.

Moderneissa 64-bittisissä Linux- ja macOS-järjestelmissä standardi on System V AMD64 ABI. Keskitymme tähän käytäntöön.

Assemblyn julkinen rajapinta

Jotta C voi kutsua assembly-funktiota, se on määritettävä globaaliksi. Tämä kertoo linkittäjälle, että funktiota voidaan käyttää muista tiedostoista.

Perusrakenne näyttää tältä:

  • Käytä global-direktiiviä.
  • Määritä funktio tunnisteella (usein alaviivalla alkavalla, kuten _my_function, vaikka System V ABI ei sitä ehdottomasti edellytä; kyseessä on yleinen käytäntö).
  • Lisää assembly-käskysi.
  • Päätä ret-käskyyn, joka palauttaa ohjauksen kutsujalle.
section .text
global _my_function
_my_function:
    ; Your assembly code here
    ret

C:n näkökulma assemblyyn

C:n näkökulmasta assembly-funktio on aivan kuin mikä tahansa muualla määritelty funktio. Se ilmoitetaan extern-avainsanalla.

C:n funktioprototyypin on vastattava täsmälleen sitä, mitä assembly-funktio odottaa argumenttien ja palautustyypin osalta.

Jos assembly-funktiosi ottaa kaksi long-kokonaislukua ja palauttaa long-arvon, C-prototyyppi olisi esimerkiksi: extern long my_assembly_func(long a, long b);

extern long my_assembly_func(long a, long b);

Datan välittäminen assemblylle

System V AMD64 ABI -käytännön mukaan kuusi ensimmäistä kokonaisluku- tai osoitinargumenttia välitetään tiettyjen rekisterien kautta:

  • 1. argumentti: RDI
  • 2. argumentti: RSI
  • 3. argumentti: RDX
  • 4. argumentti: RCX
  • 5. argumentti: R8
  • 6. argumentti: R9

Mahdolliset lisäargumentit työnnetään pinoon oikealta vasemmalle.

Tulosten palauttaminen

Kun assembly-funktiosi suoritus päättyy, se sijoittaa palautusarvon tiettyyn rekisteriin, josta C voi lukea sen.

  • Kokonaisluku- tai osoitinpalautusarvoille käytetään RAX-rekisteriä.
  • Liukulukuarvoille käytetään XMM0-rekisteriä.

Sijoitettuaan tuloksen assembly-funktio suorittaa yksinkertaisesti ret-käskyn ja palaa sitä kutsuneeseen C-koodiin.

Lukujen yhteenlasku: C kutsuu assemblyä (ASM)

Luodaan assembly-funktio, joka laskee yhteen kaksi lukua. Tiedoston nimi olisi yleensä my_add.asm.

Kiinnittäkää huomiota siihen, miten argumentit vastaanotetaan rekistereissä RDI ja RSI ja miten tulos sijoitetaan rekisteriin RAX.

; my_add.asm
section .text
global add_two_numbers

add_two_numbers:
    ; RDI holds the first argument (a)
    ; RSI holds the second argument (b)
    mov rax, rdi    ; Move 'a' into RAX
    add rax, rsi    ; Add 'b' to RAX (RAX = a + b)
    ret             ; Return to caller (RAX holds the result)

Lukujen yhteenlasku: C kutsuu assemblyä (C)

Kirjoitetaan nyt C-koodi, joka käyttää assembly-funktiotamme. Tiedoston nimi olisi yleensä main.c. Muistakaa ilmoittaa funktio extern-määreellä.

Kääntäkää ja linkittäkää näin:

nasm -f elf64 my_add.asm -o my_add.o

gcc main.c my_add.o -o my_program

./my_program

// main.c
#include <stdio.h>

// Declare the assembly function
extern long add_two_numbers(long a, long b);

int main() {
    long num1 = 10;
    long num2 = 25;
    long sum;

    // Call the assembly function
    sum = add_two_numbers(num1, num2);

    printf("The sum of %ld and %ld is %ld\n", num1, num2, sum);

    return 0;
}

Rekisterien suojaaminen

Assembly-funktiosi saattaa käyttää suorituksensa aikana useita rekistereitä. Jotkin rekisterit ovat kutsujan säilyttämiä (kutsujan on tallennettava ne, jos se tarvitsee niitä myöhemmin), kun taas toiset ovat kutsutun säilyttämiä (assembly-funktion on tallennettava ja palautettava ne, jos se muuttaa niiden arvoja).

Yleisiä kutsutun säilyttämiä rekistereitä (x64) ovat: RBX, RBP, RSP, R12, R13, R14, R15.

Jos assembly-funktiosi muuttaa kutsutun säilyttämää rekisteriä, sen arvo on tallennettava alussa PUSH-käskyllä ja palautettava ennen paluuta POP-käskyllä.

_my_function_with_preservation:
    push rbx      ; Save RBX
    ; ... use RBX ...
    pop rbx       ; Restore RBX
    ret

Pikatesti

Mikä rekisteri sisältäisi yleensä kolmannen C:stä assembly-funktiolle välitetyn kokonaislukuargumentin System V AMD64 ABI -käytännön mukaan?

Kertaus: C:n ja assemblyn yhdistäminen

Hienoa työtä! Olette oppineet assembly-koodin kutsumisen perusteet C:stä.

  • Ymmärsitte, miksi C ja assembly kannattaa linkittää toisiinsa.
  • Tutustuimme kutsukäytäntöihin ja keskityimme System V AMD64 ABI -käytäntöön.
  • Näitte, miten funktioita ilmoitetaan sekä assemblyn että C:n puolella.
  • Opitte, miten argumentit välitetään (rekistereissä) ja miten palautusarvot vastaanotetaan (RAX-rekisterissä).
  • Tarkastelimme lyhyesti rekisterien säilyttämistä koskevia sääntöjä odottamattomien sivuvaikutusten välttämiseksi.

Tämä taito on tärkeä matalan tason optimoinnissa ja järjestelmän kanssa vuorovaikutuksessa!

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 ”Assemblyn kutsuminen C:stä” ilmainen?

Kyllä – oppitunnin ”Assemblyn kutsuminen C:stä” 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 ”Assemblyn kutsuminen C:stä”?

Opiskelkaa integroimaan assembly-rutiineja C/C++-projekteihin, välittämään parametreja ja vastaanottamaan paluuarvoja kutsukäytäntöjen avulla. 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 1/4.

Kuinka kauan ”Assemblyn kutsuminen C:stä”-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. Assemblyn kutsuminen C:stä
  2. C:n kutsuminen assemblysta
  3. Monikielisen ohjelmoinnin tekniikat
  4. Kutsukäytännöt: cdecl, stdcall ja System V
← Takaisin: Assembly-kieli ja x86-tason järjestelmäohjelmointi