Luokka-arkisto: Books on Assembler. Kokoamisen perusteet

Olemme vaalineet tätä ajatusta pitkään. Me luultavasti hyökkäsimme sitä joka puolelta useita vuosia, ja joka kerta, kun jokin tuli tiellemme. Toisaalta assembler on yhtä siistiä kuin kyky kommunikoida tietokoneen kanssa sen kielellä voi olla siistiä lukija-hakkerillemme (krakkeri, käänteinen). Toisella puolella - nykyiset käsikirjat ASMA:n mukaan, tämän vuosisadan julkaisut mukaan lukien, niitä on tarpeeksi, ja nykyään on liberaalia, verkkohakkerit ja JS:n ystävät eivät ehkä ymmärrä tai hyväksy meitä. 🙂 Menestys teki lopun fyysikkojen, sanoittajien, vanhauskoisten, nikonilaisten, verkkohakkereiden ja työvoiman murtautujien väliselle kiistalle. Kävi ilmi, että nyt, 2000-luvulla, työvoiman krakkarit eivät ole vieläkään luopuneet asemistaan ​​ja lukijamme ovat kiinnostuneita tästä!

Mutta mitä on ohjelmointi pohjimmiltaan, kielestä riippumatta? Vastausten monimuotoisuus on hämmästyttävää. Useimmiten voit kuulla tämän määritelmän: ohjelmointi on käskyjen tai komentojen kokoamista koneen peräkkäiseen suorittamiseen tietyn ongelman ratkaisemiseksi. Tämä vastaus on varsin oikeudenmukainen, mutta mielestäni se ei heijasta täyteyttä, ikään kuin kutsuisimme kirjallisuutta lauseiden sanakokoelmaksi lukijan peräkkäistä lukemista varten. Olen taipuvainen uskomaan, että ohjelmointi on lähempänä luovuutta, taidetta. Kuten mikä tahansa taide - luovien ajatusten, ideoiden ilmaisu, ohjelmointi on heijastus ihmisen ajattelusta. Idea voi olla sekä loistava että täysin keskinkertainen.

Mutta riippumatta siitä, millaista ohjelmointia teemme, menestys riippuu käytännön taidoista yhdistettynä tietoon perusasiat ja teorioita. Teoria ja käytäntö, opiskelu ja työ - nämä ovat menestymisen kulmakiviä.

SISÄÄN Viime aikoina assembler on ansaitsemattomasti muiden kielten varjossa. Tämä johtuu maailmanlaajuisesta kaupallistamisesta, jonka tavoitteena on maksimointi lyhyt aika saada tuotteesta mahdollisimman paljon voittoa. Toisin sanoen massaluonne on voittanut elitismin. Ja assembler on mielestäni lähempänä jälkimmäistä. On paljon kannattavampaa kouluttaa opiskelija suhteellisen lyhyessä ajassa esimerkiksi kielillä, kuten C++, C#, PHP, Java, JavaScript, Python, jotta hän pystyy enemmän tai vähemmän luomaan kuluttajatason ohjelmistoja. esittämättä kysymyksiä siitä, miksi ja miksi hän tekee niin, kuin vapauttaa hyvä asiantuntija kokoonpanossa. Esimerkki tästä on laajat markkinat kaikenlaisille ohjelmointikursseille millä tahansa kielellä, lukuun ottamatta kokoonpanoa. Sama suuntaus näkyy sekä yliopistoopetuksessa että oppikirjallisuudessa. Molemmissa tapauksissa jopa tänään Suurin osa materiaalista perustuu varhaisiin 8086-sarjan prosessoreihin, ns. "oikeaan" 16-bittiseen käyttötilaan, MS-DOS ympäristö! On mahdollista, että yksi syy on se, että toisaalta IBM:n PC-tietokoneiden tultua opettajien oli vaihdettava tähän nimenomaiseen alustaan, koska muut eivät olleet käytettävissä. Toisaalta 80x86-linjan kehittyessä kyky ajaa ohjelmia DOS-tilassa säilyi, mikä mahdollisti rahan säästämisen uusien koulutustietokoneiden hankinnassa ja oppikirjojen kokoamisessa uusien prosessorien arkkitehtuurin tutkimiseen. Nyt tällainen opiskelualustan valinta on kuitenkin täysin mahdotonta hyväksyä. MS-DOS ohjelman suoritusympäristönä oli toivottoman vanhentunut 1990-luvun puoliväliin mennessä, ja siirtymisen myötä 32-bittisiin prosessoreihin, alkaen 80386-prosessorista, itse komentojärjestelmästä tuli paljon loogisempi. Joten on turha tuhlata aikaa arkkitehtuurin omituisuuksien tutkimiseen ja selittämiseen todellinen tila, joka ei varmasti koskaan näy missään prosessorissa.

Mitä tulee käyttöympäristön valintaan assemblerin oppimiseen, niin jos puhumme 32-bittisestä käskyjärjestelmästä, valinta on suhteellisen pieni. Nämä joko toimivat Windows-järjestelmät, tai UNIX-perheen edustajia.

Sinun tulisi myös sanoa muutama sana siitä, mikä kokoaja valita tiettyyn toimintaympäristöön. Kuten tiedät, x86-prosessorien kanssa työskentelyyn käytetään kahden tyyppistä assembler-syntaksia - AT&T-syntaksia ja Intel-syntaksia. Nämä syntaksit edustavat samoja komentoja täysin eri tavoilla. Esimerkiksi Intelin syntaksin komento näyttää tältä:

Mov eax, ebx

AT&T-syntaksilla on eri muoto:

Movl %eax,%ebx

AT&T-tyyppinen syntaksi on kuitenkin suositumpi UNIX-käyttöjärjestelmäympäristössä opetusvälineet siitä ei ole tietoa, se on kuvattu yksinomaan viitteessä ja teknisessä kirjallisuudessa. Siksi on loogista valita Intelin syntaksiin perustuva kokoaja. UNIX-järjestelmissä on kaksi pääasentajaa - NASM (Netwide Assembler) ja FASM (Flat Assembler). varten Windows linjat Microsoftin FASM ja MASM (Macro Assembler) ovat suosittuja, ja mukana oli myös TASM (Turbo Assembler) Borlandilta, joka on kauan sitten lopettanut oman luomuksensa tukemisen.

Tässä artikkelisarjassa tutkimme Windows-ympäristö perustuu MASM-kokoonpanokieleen (yksinkertaisesti siksi, että pidän siitä paremmin). Monet kirjailijat mukana alkuvaiheessa learning assembler sopii sen C-kielen kuoreen sillä perusteella, että käyttöympäristössä on oletettavasti melko vaikeaa siirtyä käytännön esimerkkeihin: siinä pitää osata sekä ohjelmoinnin perusteet että prosessorin komennot. Tämä lähestymistapa vaatii kuitenkin myös C-kielen pienimmätkin alkeet. Tämä artikkelisarja keskittyy alusta alkaen vain itse kokoajaan sekoittamatta lukijaa mihinkään muuhun hänelle käsittämättömään, vaikka tulevaisuudessa yhteys muihin kieliin voidaankin jäljittää.

On syytä huomata, että ohjelmoinnin perusteiden oppimisessa, ja tämä ei koske vain kokoonpanoohjelmointia, on erittäin hyödyllistä ymmärtää konsolisovellusten kulttuuri. Ja on täysin ei-toivottavaa aloittaa oppiminen välittömästi luomalla ikkunoita, painikkeita, eli ikkunoiduilla sovelluksilla. On olemassa mielipide, että konsoli on arkaainen menneisyyden jäänne. Se ei kuitenkaan ole. Konsolisovellus on lähes vailla ulkopuolista riippuvuutta ikkunakuoresta ja se on keskittynyt pääasiassa tietyn tehtävän suorittamiseen, mikä tarjoaa erinomaisen mahdollisuuden keskittyä ohjelmoinnin ja kokoonpanon perusasioiden oppimiseen ilman, että mikään muu häiritsee sinua. itse, mukaan lukien tuntemus algoritmeihin ja niiden kehittämiseen ratkaistavaksi käytännön ongelmia. Ja kun tulee aika siirtyä tutustumaan ikkunallisia sovelluksia, sinulla on jo takanasi vaikuttava tietokanta, selkeä käsitys prosessorin toiminnasta ja mikä tärkeintä, tietoisuus toimistasi: miten ja mikä toimii, miksi ja miksi.

Mikä on assembler?

Itse sana kokoaja(assembler) on käännetty englannista "assembler". Itse asiassa tämä on käännösohjelman nimi, joka ottaa syötteeksi tekstin, joka sisältää ihmisille sopivien konekäskyjen symboleja, ja kääntää nämä symbolit vastaavien koneen komentokoodien sarjaksi, jotka prosessori ymmärtävät. Toisin kuin koneen ohjeet, niiden yleissopimuksia kutsutaan myös muistitekniikka, ovat suhteellisen helppo muistaa, koska ne ovat englanninkielisten sanojen lyhenteitä. Seuraavassa viitataan yksinkertaisuuden vuoksi muistotekniikkaan assembler-komentoina. Sopimuksen kieltä kutsutaan kokoonpanokieli.

Tietokoneajan kynnyksellä ensimmäiset tietokoneet miehittivät kokonaisia ​​huoneita ja painoivat yli tonnin, ja niillä oli varpusen aivojen muistikapasiteetti tai jopa vähemmän. Ainoa tapa ohjelmoida siihen aikaan oli ajaa ohjelma suoraan tietokoneen muistiin digitaalisessa muodossa vaihtokytkimiä, johtoja ja painikkeita vaihtamalla. Tällaisten kytkimien määrä saattoi nousta useisiin satoihin ja kasvoi ohjelmien monimutkaistuessa. Heräsi kysymys ajan ja rahan säästämisestä. Siksi seuraava kehitysaskel oli viime vuosisadan 40-luvun lopulla ilmestynyt ensimmäinen kääntäjä-asentaja, joka mahdollisti konekäskyjen kirjoittamisen kätevästi ja yksinkertaisesti. ihmisen kieli ja tämän seurauksena automatisoi koko ohjelmointiprosessin, yksinkertaistaa ja nopeuttaa ohjelmien kehitystä ja virheenkorjausta. Sitten tulivat kielet korkeatasoinen Ja kääntäjät(älykkäämpiä koodigeneraattoreita ihmisen luettavammasta kielestä) ja tulkit(ihmisen kirjoittaman ohjelman toteuttajat lennossa). Ne paranivat ja paranivat - ja lopulta tuli siihen pisteeseen, että voit yksinkertaisesti ohjelmoida hiirellä.

Kokoonpanija on siis konesuuntautunut kieli ohjelmointi, jonka avulla voit työskennellä tietokoneen kanssa suoraan, yksitellen. Tästä syystä sen täydellinen muotoilu - toisen sukupolven matalan tason ohjelmointikieli (jälkeen konekoodi). Assembler-komennot vastaavat yksi yhteen prosessorin komentoja, mutta koska niitä on erilaisia ​​malleja prosessorit, joilla on omat käskysarjansa, on vastaavasti kokoonpanokielen lajikkeita tai murteita. Siksi termin "assembly language" käyttö voi johtaa siihen väärinkäsitykseen, että tällaisille kielille on olemassa yksi matala kieli tai ainakin standardi. Se ei ole olemassa. Siksi nimeäessään kieltä, jolla tietty ohjelma kirjoitetaan, on tarpeen selvittää, mihin arkkitehtuuriin se on tarkoitettu ja millä kielen murteella se on kirjoitettu. Koska kokoaja on sidottu prosessorilaitteeseen, ja prosessorityyppi määrittää tiukasti joukon käytettävissä olevia komentoja konekieli, kokoonpanokieliset ohjelmat eivät ole siirrettävissä muihin tietokonearkkitehtuureihin.

Koska assembler on vain henkilön kirjoittama ohjelma, mikään ei estä toista ohjelmoijaa kirjoittamasta omaa assembleriään, mitä usein tapahtuu. Itse asiassa ei ole niin tärkeää, mitä assembly-kieltä opiskellaan. Tärkeintä on ymmärtää toimintaperiaate prosessorin komentojen tasolla, ja sitten ei ole vaikeaa hallita paitsi toista kokoavaa, myös mitä tahansa muuta prosessoria, jolla on oma komentosarja.

Syntaksi

Assembly-kielten syntaksille ei ole yleisesti hyväksyttyä standardia. Useimmat assembly-kielten kehittäjät noudattavat kuitenkin yleisiä perinteisiä lähestymistapoja. Tärkeimmät tällaiset standardit ovat Intelin syntaksi Ja AT&T syntaksi.

Tallennusohjeiden yleinen muoto on sama molemmissa standardeissa:

[tunniste:] opcode [operandit] [;kommentti]

Opcode on itse asiassa kokoonpanokomento, prosessorin ohjeiden muistiinpano. Siihen voidaan lisätä etuliitteitä (esim. toistoja, muutoksia osoitetyypissä). Operandit voivat olla vakioita, rekisterien nimiä, osoitteita RAM-muistissa ja niin edelleen. Intelin ja AT&T:n standardien väliset erot liittyvät pääasiassa järjestykseen, jossa operandit luetellaan ja niiden syntaksiin, kun erilaisia ​​menetelmiä osoitteleminen.

Käytetyt komennot ovat yleensä samat kaikille saman arkkitehtuurin tai arkkitehtuuriperheen prosessoreille (tunnettuja ovat komennot Motorola-, ARM-, x86-suorittimille ja ohjaimille). Ne on kuvattu prosessorin teknisissä tiedoissa.

Jotta kone voisi suorittaa ihmisen käskyjä laitteistotaso, on tarpeen asettaa tietty toimintosarja "nollien ja ykkösten" kielellä. Kokoonpanijasta tulee avustaja tässä asiassa. Tämä on apuohjelma, joka toimii komentojen kääntämisen kanssa konekieli. Ohjelman kirjoittaminen on kuitenkin erittäin työläs ja monimutkainen prosessi. Tätä kieltä ei ole tarkoitettu luomaan keuhkoja ja yksinkertaisia ​​toimia. Päällä Tämä hetki millä tahansa ohjelmointikielellä (Assembler toimii hyvin) voit kirjoittaa erityisiä, tehokkaita tehtäviä, jotka vaikuttavat suuresti laitteiston toimintaan. Päätarkoituksena on luoda mikrokäskyjä ja pieniä koodeja. Tämä kieli antaa lisää mahdollisuuksia kuin esimerkiksi Pascal tai C.

Lyhyt kuvaus kokoonpanokielistä

Kaikki ohjelmointikielet on jaettu tasoihin: matala ja korkea. Mikä tahansa Assembler-perheen syntaktinen järjestelmä erottuu siitä, että se yhdistää kerralla joitain yleisimpien ja yleisimpien järjestelmien etuja. modernit kielet. Heillä on yhteistä muiden kanssa, että he voivat käyttää tietokonejärjestelmää täysimääräisesti.

Kääntäjän erottuva piirre on sen helppokäyttöisyys. Tämä erottaa sen niistä, jotka toimivat vain korkeilla tasoilla. Jos harkitset jotakin tällaista ohjelmointikieltä, Assembler toimii kaksi kertaa nopeammin ja paremmin. Kevyen ohjelman kirjoittaminen siihen ei vie liikaa aikaa.

Lyhyesti kielen rakenteesta

Jos puhumme yleisesti kielen toiminnasta ja rakenteesta, voimme varmasti sanoa, että sen komennot vastaavat täysin prosessorin komentoja. Toisin sanoen assembler käyttää useimmiten muistokoodeja mukava ihmiselle tallennusta varten.

Toisin kuin muut ohjelmointikielet, Assembly käyttää muistisolujen kirjoittamiseen erityisiä tarroja osoitteiden sijaan. Yhdessä koodin suoritusprosessin kanssa ne käännetään niin sanotuiksi direktiiveiksi. Tämä suhteelliset osoitteet, jotka eivät vaikuta prosessorin toimintaan (ei ole käännetty konekielelle), mutta ovat välttämättömiä ohjelmointiympäristön itsensä tunnistamiseksi.

Jokaisella prosessorin rivillä on omat prosessinsa. Tässä tilanteessa mikä tahansa prosessi, myös käännetty, on oikea

Assembly-kielellä on useita syntakseja, joita käsitellään artikkelissa.

Kielen plussat

Assembly-kielen tärkein ja kätevin laite on, että voit kirjoittaa siihen minkä tahansa ohjelman prosessorille, joka on erittäin kompakti. Jos koodi osoittautuu valtavaksi, jotkut prosessit ohjataan uudelleen RAM-muistiin. Lisäksi he tekevät kaiken melko nopeasti ja ilman vikoja, ellei niitä tietenkään johda pätevä ohjelmoija.

Ohjaimet, käyttöjärjestelmät, BIOS, kääntäjät, tulkit jne. ovat kaikki Assembly-kielisiä ohjelmia.

Kun käytät disassembler-laitetta, joka suorittaa käännöksen koneelta koneelle, voit helposti ymmärtää, kuinka tämä tai toinen järjestelmätehtävä toimii, vaikka sille ei olisi selitystä. Tämä on kuitenkin mahdollista vain, jos ohjelmat ovat helppoja. Valitettavasti ei-triviaaleja koodeja on melko vaikea ymmärtää.

Kielen haitat

Valitettavasti aloittelevien ohjelmoijien (ja usein ammattilaisten) on vaikea ymmärtää kieltä. Kokoonpanija vaatii yksityiskohtaisen kuvauksen vaaditusta komennosta. Konekomentojen käytön tarpeesta johtuen virheellisten toimien todennäköisyys ja suorituksen monimutkaisuus kasvavat.

Yksinkertaisimmankin ohjelman kirjoittaminen edellyttää ohjelmoijan pätevyyttä ja riittävän korkeaa tietämystä. Keskivertoasiantuntija kirjoittaa valitettavasti usein huonoa koodia.

Jos alusta, jolle ohjelma on luotu, päivitetään, kaikki komennot on kirjoitettava uudelleen manuaalisesti - tämä edellyttää itse kieliä. Kokoonpanija ei tue toimintoa automaattinen säätö prosessien toimivuus ja mahdollisten elementtien korvaaminen.

Kielikomennot

Kuten edellä mainittiin, jokaisella prosessorilla on omat komentosarjansa. Yksinkertaisimmat minkä tahansa tyypin tunnistamat elementit ovat seuraavat koodit:


Direktiivien käyttö

Mikrokontrollerien ohjelmointi alimman tason kielellä (Assembler sallii tämän ja selviää hyvin) päättyy useimmiten onnistuneesti. On parasta käyttää prosessoreita rajoitettu resurssi. Tämä kieli sopii täydellisesti 32-bittiselle tekniikalle. Voit usein huomata koodeissa ohjeita. Mikä tämä on? Ja mihin sitä käytetään?

Ensinnäkin on korostettava, että direktiivejä ei käännetä konekielelle. Ne säätelevät kuinka kääntäjä tekee työn. Toisin kuin komennot, nämä parametrit, joilla erilaisia ​​toimintoja, eivät eroa eri prosessoreista, vaan erilaisesta kääntäjästä. Tärkeimpiä direktiivejä ovat seuraavat:


nimen alkuperä

Kuinka kieli sai nimensä - "Assembler"? Puhumme kääntäjästä ja kääntäjästä, jotka salaavat tiedot. Englanniksi Assembler ei tarkoita muuta kuin kokoajaa. Ohjelmaa ei koottu käsin, vaan käytettiin automaattista rakennetta. Lisäksi tällä hetkellä käyttäjät ja asiantuntijat ovat jo menettäneet termien välisen eron. Ohjelmointikieliä kutsutaan usein assembleriksi, vaikka se on vain apuohjelma.

Yleisen kollektiivisen nimen vuoksi jotkut ihmiset uskovat virheellisesti, että on olemassa yksi matalan tason kieli (tai sen standardinormit). Jotta ohjelmoija ymmärtäisi, mistä rakenteesta puhumme, on tarpeen selvittää, mille alustalle tiettyä Assembly-kieltä käytetään.

Makro tarkoittaa

Assembly-kielillä, jotka on luotu suhteellisen äskettäin, on makrotoiminnot. Ne helpottavat ohjelman kirjoittamista ja suorittamista. Niiden läsnäolon ansiosta kääntäjä suorittaa kirjoitetun koodin monta kertaa nopeammin. Kun luot ehdollisen valinnan, voit kirjoittaa valtavan määrän komentoja, mutta makrotyökalujen käyttö on helpompaa. Niiden avulla voit vaihtaa nopeasti toimien välillä, jos jokin ehto täyttyy vai ei.

Makrokielen käskyjä käytettäessä ohjelmoija vastaanottaa Assembler-makroja. Joskus sitä voidaan käyttää laajalti, ja joskus sitä toiminnallisia ominaisuuksia vähennetty yhdeksi joukkueeksi. Niiden läsnäolo koodissa helpottaa käsittelyä, mikä tekee siitä ymmärrettävämmän ja visuaalisemman. Sinun tulee kuitenkin olla varovainen - joissain tapauksissa makrot päinvastoin pahentavat tilannetta.

Alkuperäinen: Aloita asennuskielellä. Osa 1
Kirjailija: Mike Saunders
Julkaistu: 30. lokakuuta 2015
Käännös: A. Panin
Käännöspäivä: 10. marraskuuta 2015

Osa 1: Ylittää korkean tason ohjelmointikielten rajoitukset ja ymmärtää kuinka keskusyksikkö todella toimii.

Mitä varten se on?

  • Ymmärtääksesi kuinka kääntäjät toimivat.
  • Ymmärtääksesi CPU:n ohjeet.
  • Optimoi koodisi suorituskykyä varten.

Useimmat ihmiset uskovat, että kokoonpanokieli ei eroa paljon mustasta magiasta ja on osa pimeää ja pelottava maailma, johon vain 0,01 % parhaista kehittäjistä on vaarassa tulla ohjelmisto. Mutta itse asiassa se on kaunis ja erittäin helppokäyttöinen ohjelmointikieli. Sinun tulisi tutkia sen perusteita ainakin ymmärtääksesi paremmin kääntäjien koodin luomisen mekanismia, keskusprosessorien toimintaperiaatetta ja myös tietokoneiden toimintaperiaatetta. Assembly-kieli on pohjimmiltaan sen suorittamien ohjeiden tekstimuotoinen esitys. prosessori, jonkun kanssa lisäominaisuuksia, mikä yksinkertaistaa ohjelmointiprosessia.

Nykyään kukaan täysijärkinen ei kehittyisi tehokas sovellus varten pöytätietokone assembly-kielellä. Loppujen lopuksi tällaisen sovelluksen koodi on liian hämmentävä, sovelluksen virheenkorjausprosessi on paljon monimutkaisempi, ja lisäksi on tehtävä valtavia ponnisteluja tämän sovelluksen siirtämiseksi toimimaan muiden keskussuoritinarkkitehtuurien kanssa. Mutta samaan aikaan kokoonpanokieltä käytetään edelleen useisiin tarkoituksiin: monet Linux-ytimeen sisältyvät ajurit sisältävät koodinpätkät assembly-kielellä, jota käytetään molempien, koska se on paras kieli ohjelmointi suoraa vuorovaikutusta varten laitteiston kanssa ja ajurien nopeuden lisäämiseksi. myös sisällä tietyissä tapauksissa Assembly-kielellä käsin kirjoitettu koodi voi toimia nopeammin kuin koodi, kääntäjän luoma.

Tämän sarjan artikkeleissa tutkimme kokoonpanokielen maailmaa yksityiskohtaisesti. Tässä artikkelissa tarkastellaan vain perusohjelmointitekniikoita, lehden seuraavan numeron artikkelissa käsittelemme monimutkaisempia asioita, minkä jälkeen lopetamme kokoonpanokielen pohdiskelun kirjoittamalla yksinkertaisen latauksen käyttöjärjestelmä- hän ei pysty suorittamaan mitään hyödyllistä työtä, mutta se perustuu koodiisi ja toimii suoraan laitteiston kanssa ilman, että sinun tarvitsee ladata kolmannen osapuolen käyttöjärjestelmää. Kuulostaa hyvältä, eikö? aloitetaan

Ensimmäinen assembly-kieliohjelmasi

Monet kokoonpanokielen ohjelmointiopetusohjelmat alkavat pitkillä, hämmentävällä ja tylsällä osilla, jotka jatkavat binaariaritmetiikkaa ja suorittimen suunnitteluteoriaa sisältämättä varsinaista koodia. Uskon, että tällaiset materiaalit mitätöivät lukijan kiinnostuksen, joten aloitamme suoraan koodin tarkistamisesta oikea ohjelma. Sen jälkeen tarkastellaan tämän ohjelman jokaista koodiriviä, jotta ymmärrät kokoonpanokielen periaatteen käytännön esimerkin perusteella.

Jotkut tekstieditorit, kuten Vim, tarjoavat kokoonpanokielen syntaksin korostuksen (kokeile set syn=nasm -komentoa)

Kopioi seuraava koodi minkä tahansa tekstikenttään tekstieditori ja tallenna se kotihakemistoosi tiedostoon myfirst.asm:

Section .text global _start _start: mov ecx, viesti mov edx, pituus mov ebx, 1 mov eax, 4 int 0x80 mov eax, 1 int 0x80 section .data message db "Kokoonpanosäännöt!", 10 pituus equ $ - viesti

(Huomaa: Voit käyttää välilyöntejä tai sarkaimia sisentääksesi koodisi - sillä ei ole väliä.) Tämä ohjelma yksinkertaisesti tulostaa rivin "Kokoonpanosäännöt!" näytölle ja poistuu.

Työkalulla, jota käytämme tämän kokoonpanokielen koodin muuntamiseen suoritettavaksi binääritiedostoksi, on melko huvittava nimi "assembler". Kokoonpanijoita on monia, mutta suosikkini kokoonpanija on NASM; se on melkein minkä tahansa jakelun ohjelmistopakettivarastossa, joten voit asentaa sen käyttämällä ohjelmistopakettien hallintaa graafinen käyttöliittymä, yum install nasm , apt-get install nasm tai mikä tahansa muu jakelullesi liittyvä komento.

Avaa nyt pääteemulaattori-ikkuna ja kirjoita seuraavat komennot:

Nasm -f elf -o myfirst.o myfirst.asm ld -m tonttu_i386 -o myfirst myfirst.o

Ensimmäinen komento on luoda objektikooditiedosto nimeltä myfirst.o käyttämällä NASM:ää (Linuxissa käytetty suoritettava tiedostomuoto). Saatat kysyä: "Miksi objektikooditiedosto luodaan, koska olisi loogisempaa luoda tiedosto, jossa on ohjeet keskusprosessorille, jotka sen tulisi suorittaa?" No, voit käyttää suoritettavaa tiedostoa CPU-käskyillä 80-luvun käyttöjärjestelmissä, mutta nykyaikaisissa käyttöjärjestelmissä on suoritettaville tiedostoille enemmän vaatimuksia. ELF-binäärit sisältävät virheenkorjaustietoja ja mahdollistavat koodin ja datan erottamisen erillisillä osioilla, jotta estetään näiden osien tietojen päällekirjoittaminen.

Myöhemmin harkitessamme menetelmää koodin kirjoittamiseksi suoraan laitteiston kanssa toimimaan (minimalistiselle käyttöjärjestelmällemme), osana tätä artikkelisarjaa, kiinnitämme huomiota tällaisiin binääritiedostoihin keskusprosessorin ohjeilla.

Katsaus menneisyyteen

Tällä hetkellä meillä on käytössämme tiedosto myfirst.o, jossa on ohjelmamme suoritettava koodi. Ohjelman rakentamisprosessia ei kuitenkaan ole vielä saatu päätökseen. Käyttämällä ld-linkkeriä meidän on linkitettävä tämän tiedoston koodi erityiseen järjestelmän käynnistyskoodiin (eli vakiokoodiin, joka suoritetaan jokaisen ohjelman käynnistyessä) luodaksemme sen. suoritettava tiedosto nimeltä myfirst. (Parametri elf_i386 kuvaa binäärimuodon tyyppiä - in tässä tapauksessa tämä tarkoittaa, että voit käyttää 32-bittistä kokoonpanokoodia, vaikka käytät 64-bittistä jakelua.)

Jos rakennusprosessi ohjelma järjestetään onnistuneesti, voit suorittaa ohjelman käyttämällä seuraavaa komentoa:

Tämän seurauksena sinun pitäisi nähdä tulos: "Kokoamissäännöt!". Tämä tarkoittaa, että olet saavuttanut tavoitteesi - olet luonut Linuxille täysimittaisen itsenäisen ohjelman, jonka koodi on kirjoitettu kokonaan assembly-kielellä. Tietysti Tämä ohjelma ei suorita yhtään hyödyllisiä toimia, mutta samalla se on erinomainen esimerkki, joka osoittaa ohjelman rakenteen assembly-kielellä ja mahdollistaa muuntoprosessin jäljittämisen lähdekoodi binääritiedostoon.

Ennen kuin sukeltaamme koodiin, olisi hyvä tietää ohjelmamme binaaritiedoston koko. Kun olet suorittanut ls -l myfirst -komennon, näet, että binääritiedoston koko on noin 670 tavua. Arvioidaan nyt vastaavan ohjelman koko C:ssä:

#sisältää int main() ( puts("Kokoonpanosäännöt!"); )

Jos tallennat tämän koodin tiedostoon, jonka nimi on test.c , käännät sen (gcc -o test test.c ) ja katsot tuloksena olevan testin binaaritiedoston parametreja, huomaat, että tässä tiedostossa on paljon suurempi koko- 8,4k. Voit poistaa tästä tiedostosta virheenkorjaustiedot(kaistale -s testi), mutta tämänkin jälkeen sen koko pienenee hieman, vain 6 kilometriin. Tämän selittää GCC-kääntäjä lisää suuren määrän yllä mainittua koodia sovelluksen käynnistämiseksi ja pysäyttämiseksi, ja myös linkittää sovelluksen C-ohjelmointikielikirjastoon iso koko. Kiitokset tämä esimerkki On helppo päätellä, että assembly-kieli on paras ohjelmointikieli käytettäväksi tarkoitettujen sovellusten kehittämiseen Rankat olosuhteet tallennusvälineiden kapasiteettirajoitukset.

On syytä mainita, että monet assembly-kielen kehittäjät saavat erinomaisia ​​palkkoja koodin kehittämisestä resurssirajoitteisille sulautetuille laitteille, ja siksi assembly-kieli on ainoa todellinen vaihtoehto kehittää pelejä vanhemmille 8-bittisille konsoleille ja kotitietokoneille.

Koodin purkaminen

Uuden koodin kehittäminen on hauskaa, mutta sitäkin enemmän mielenkiintoista toimintaa voi osoittautua jonkun muun työn tutkimukseksi. Objdump-nimisen työkalun (Binutils-paketista) ansiosta voit "purkaa" suoritettavan tiedoston, eli muuntaa suorittimen ohjeet tekstivastineiksi. Kokeile käyttää tätä työkalua ensimmäistä binaariohjelmaa vastaan, jota työstelimme tässä opetusohjelmassa, kuten tämä:

Objdump -d -M intel myfirst

Näet luettelon ohjeista binaaritiedoston koodiosiosta. Esimerkiksi ensimmäinen ohje, jolla asetimme tiedot merkkijonomme sijainnista ecx-rekisteriin, näyttää tältä:

Mov ecx,0x80490a0

Kokoonpanon aikana NASM korvasi "viesti"-rivin etiketin numeerinen arvo, joka vastaa tämän rivin sijaintia binaaritiedoston tietoosassa. Näin ollen binääritiedostojen purkamisen tulokset ovat vähemmän hyödyllisiä kuin niiden alkuperäinen koodi, koska niistä puuttuu esimerkiksi kommentteja ja rivejä, mutta niistä voi silti olla hyötyä aikakriittisten toimintojen toteutuksissa tai sovellusten suojausjärjestelmien rikkomisessa. Esimerkiksi 80- ja 90-luvuilla monet kehittäjät käyttivät ohjelmiston purkutyökaluja pelien kopiosuojausjärjestelmien tunnistamiseen ja neutraloimiseen.

Voit myös purkaa muilla ohjelmointikielillä kehitettyjä ohjelmia, mutta purkamisen tulokset voivat olla huomattavasti monimutkaisempia. Voit esimerkiksi suorittaa yllä olevan objdump-komennon /bin/ls-binaaritiedostoa vastaan ​​ja arvioida itsenäisesti kääntäjän luomat tuhansia rivejä koodiosia apuohjelman alkuperäisen C-lähdekoodin perusteella.

Koodianalyysi

Keskustellaan nyt ohjelmamme kunkin koodirivin tarkoituksesta. Aloitetaan näillä kahdella rivillä:

Osa .text global _start

Nämä eivät ole CPU-ohjeita, vaan assembler-ohjeita. NASM; Ensimmäinen ohje sanoo, että alla olevan koodin tulee sijaita viimeisen suoritettavan tiedoston "teksti"-koodiosassa. Hieman epäselvä on se tosiasia, että "teksti"-niminen osio ei sisällä tavallista tekstidataa (kuten "Kokoonpanosäännöt!" -rivimme), mutta suoritettava koodi, eli keskusprosessorin ohjeita. Seuraavana on globaali _start-direktiivi, joka kertoo ld-linkkerille, missä vaiheessa tiedostomme koodin suorittamisen tulisi alkaa. Tämä ohje voi olla erityisen hyödyllinen, jos haluamme aloittaa koodin suorittamisen ei aivan koodiosan alusta, vaan jostain tietystä kohdasta. Globaali parametri mahdollistaa tämän direktiivin lukemisen paitsi kokoajan, myös muiden työkalujen toimesta, joten ld-linkkeri käsittelee sen.

Kuten edellä mainittiin, koodin suoritus on aloitettava kohdasta _start. Tästä syystä osoitamme koodissamme nimenomaisesti vastaavan sijainnin:

Yksittäisiä sanoja, joiden lopussa on kaksoispiste, kutsutaan nimiöiksi, ja ne on tarkoitettu osoittamaan koodin paikkoja, joihin voimme siirtyä (lisätietoja sarjan seuraavassa artikkelissa). Siten ohjelman suoritus alkaa tältä riviltä! Lisäksi olemme vihdoin saavuttaneet ensimmäisen oikeita ohjeita PROSESSORI:

Mov ecx, viesti

Kokoonpanokieli on pohjimmiltaan joukko muistiinpanoja suorittimen (tai konekoodin) käskyille. Tässä tapauksessa mov on yksi tällainen ohje - se voidaan kirjoittaa myös keskusprosessorille ymmärrettävässä binäärimuodossa, kuten 10001011. Mutta binääritietojen kanssa työskentely voi muuttua meille painajaiseksi, tavalliset ihmiset, joten käytämme näitä luettavampia vaihtoehtoja. Kokoonpanija yksinkertaisesti muuntaa tekstikäskyt niiden binäärivastineiksi - vaikka se voi suorittaa lisätyö, josta puhumme sarjan seuraavissa artikkeleissa.

Joka tapauksessa tämän koodirivin tarkoituksen ymmärtämiseksi meidän on ymmärrettävä myös rekisterien käsite. Keskusyksiköt eivät suorita erityistehtäviä monimutkaiset toiminnot- he yksinkertaisesti siirtävät tietoja muistissa, käyttävät sitä laskutoimitukseen ja suorittavat muita toimintoja tuloksista riippuen. Keskusprosessorilla ei ole aavistustakaan, mikä näyttö, hiiri tai tulostin on. Se yksinkertaisesti siirtää tietoja ja suorittaa useita erilaisia ​​laskutoimituksia.

Tällä hetkellä keskusprosessorin käyttämien tietojen päävarasto on RAM-pankit. Mutta koska RAM sijaitsee keskusprosessorin ulkopuolella, sen käyttö vie paljon aikaa. Kuvatun prosessin nopeuttamiseksi ja yksinkertaistamiseksi keskusyksikkö sisältää oman pienen ryhmän muistisoluja, joita kutsutaan rekistereiksi. CPU-ohjeet voivat käyttää näitä rekistereitä suoraan, ja tällä koodirivillä käytämme rekisteriä nimeltä ecx.

Se on 32-bittinen rekisteri (siis se voi tallentaa numeroita 0 - 4 294 967 295). Tarkistelemalla seuraavat rivit koodia näet, että työskentelemme myös edx-, ebx- ja eax-rekisterien kanssa - nämä ovat rekistereitä yleinen tarkoitus, jota voidaan käyttää minkä tahansa tehtävän suorittamiseen, toisin kuin erikoisrekisterit, joista opimme ensikuussa. Ja tämä on pieni selitys niille, jotka haluavat tietää rekisterinimien alkuperän: ecx-rekisteriä kutsuttiin c:ksi 8-bittisten prosessorien julkaisun aikana, minkä jälkeen se nimettiin uudelleen cx:ksi 16-bittisten arvojen ja ecx:n tallentamiseksi. 32-bittisten x bittiarvojen tallentamiseen. Joten vaikka rekisterinimet näyttävätkin nykyään hieman oudolta, vanhojen prosessorien aikoina kehittäjät käyttivät yleiskäyttöisiä rekistereitä, joilla oli erilliset nimet a, b, c ja d.

Kun aloitat, et voi lopettaa.

Yksi aiheista, joita käsittelemme ensi kuussa, on pinon käyttö, joten valmistaudumme käsittelemään sitä nyt. Pino on muistialue, johon voidaan tallentaa väliaikaisia ​​arvoja, kun rekistereitä on vapautettava muihin tarkoituksiin. Mutta useimmat tärkeä tilaisuus Pino on tapa, jolla tallennat siihen tietoja: "työnnät" arvot pinoon ja "poppaat" ne sieltä. Pino käyttää LIFO-periaatetta (last in, first out), mikä tarkoittaa, että viimeinen pinoon lisätty arvo pompataan siitä ensimmäisenä.

Kuvittele, että sinulla on esimerkiksi tyhjä Pringles-pussi ja laitat siihen tavarat seuraavassa järjestyksessä: kaksikerroksinen krakkausyksikkö, Alpha-siru ja GameCube-levy. Jos aloitat näiden asioiden poistamisen, poistat ensin GameCube-levyn, sitten Alpha-merkkisirun ja niin edelleen. Kun työskentelet kokoonpanokielellä, pinoa käytetään seuraavasti:

Push 2 push 5 push 10 pop eax pop ebx pop ecx

Kun nämä kuusi käskyä on suoritettu, eax-rekisteri sisältää arvon 10, ebx-rekisteri sisältää arvon 5 ja ecx-rekisteri arvon 2. Näin ollen pinon käyttö on erinomainen tapa tilapäisesti vapauttaa rekisterit; Jos esimerkiksi eax- ja ebx-rekistereissä on tärkeitä arvoja, mutta sinun on suoritettava nykyinen työ ennen niiden käsittelyä, voit työntää arvot pinoon, tehdä nykyisen työn ja nostaa ne pois pino, palaa edellinen tila rekisterit

Lisäksi pinoa käytetään kutsuttaessa aliohjelmia tallentamaan paluuosoite pääkoodiin. Tästä syystä sinun on oltava erityisen varovainen pinon kanssa työskennellessäsi - jos ylikirjoitat siihen tallennetut tiedot, et voi palata edelliseen paikkaan sovelluksen pääkoodissa, vaan asetat itsesi yksisuuntaiseen kaatua!

Siirrytään eteenpäin

Takaisin koodiin: mov-käsky siirtää (itse asiassa kopioi) numeron paikasta toiseen, oikealta vasemmalle. Joten tässä tapauksessa sanomme "viesti tulee sijoittaa ecx-rekisteriin". Mutta mikä on "viesti"? Tämä ei ole toinen rekisteri, se on osoitin tietojen sijaintiin. Lähellä koodin loppua, "data"-osiossa, löydät viestitunnisteen, jota seuraa db-parametri, joka osoittaa, että koodiin tulisi sijoittaa muutama tavu viestitunnisteen sijaan. Tämä on erittäin kätevää, koska meidän ei tarvitse selvittää "Assembly Regulations" -linjan tarkkaa sijaintia. tietoosiossa - voimme yksinkertaisesti viitata siihen käyttämällä viestitunnistetta. (Numero 10 rivimme jälkeen on vain symboli siirtymisestä uusi rivi, samanlainen kuin merkkijonoihin lisätty merkki \n C-ohjelmointikielen kanssa työskennellessä).

Joten laitamme merkkijonon sijaintitiedot ecx-rekisteriin. Mutta se, mitä teemme seuraavaksi, on erityisen mielenkiintoista. Kuten aiemmin mainittiin, suorittimella ei ole todellista käsitettä laitteistolaitteista - jotta voit tulostaa mitään näytölle, sinun on lähetettävä tietoja näytönohjaimelle tai siirrettävä tiedot näytönohjaimen RAM-muistiin. Mutta meillä ei ole mitään tietoa tämän näytönohjaimen RAM-muistin sijainnista, lisäksi kaikki käyttävät erilaisia ​​​​näytönohjainkortteja, ikkunajärjestelmän X-palvelinasetuksia, ikkunoiden ylläpitäjät jne. Tämän perusteella jonkin asian näyttäminen suoraan näytöllä pienellä ohjelmalla on meidän tapauksessamme käytännössä mahdotonta.

Joten pyydämme käyttöjärjestelmän ydintä tekemään tämän puolestamme. Linux-ydin tekee sen saataville matalan tason sovelluksille suuri määrä järjestelmäkutsuja, joilla sovellukset voivat käynnistää erilaisten toimintojen suorittamisen ydintasolla. Yksi näistä järjestelmäkutsuista on lähtöä varten tekstimerkkijono. Kun tätä järjestelmäkutsua käytetään, käyttöjärjestelmäydin tekee kaiken tarvittavan työn – ja tietysti se tarjoaa vielä syvemmän abstraktion tason, jossa rivi voidaan tulostaa tavallisella tekstipäätteellä, X-ikkunan järjestelmäpääteemulaattorilla tai jopa kirjoitettu aiemmin avattuun tiedostoon.

Ennen kuin käskemme käyttöjärjestelmän ydintä tulostamaan tekstijonon, meidän on kuitenkin kerrottava se Lisäinformaatio, lisäksi tiedot jo ecx-rekisterissä olevan merkkijonon sijainnista. Meidän on myös kerrottava sille, kuinka monta merkkiä se tarvitsee tulostaa, jotta rivin tulostus ei jatku sen päättymisen jälkeen. Juuri tähän käytetään sovelluskoodin lopussa olevan dataosion riviä:

Pituus equ $ - viesti

Tämä rivi käyttää eripituista nimiötä, mutta sen sijaan, että käyttäisimme db-parametria yhdistämään nimiön joihinkin tietoihin, käytämme equ-parametria osoittamaan, että tämä nimiö vastaa jotain (tämä on vähän kuin C:n #define preprocessor -direktiivi ohjelmointikieli). Dollarimerkki vastaa nykyistä sijaintia koodissa, joten tässä tapauksessa sanomme "pituusmerkinnän on vastattava koodin nykyistä sijaintia miinus "viesti" -rivin sijainti.

Palataan sovelluskoodin osioon, johon asetamme annettu arvo edx-rekisterissä:

Mov edx, pituus

Kaikki sujuu hyvin: kaksi rekisteriä on täynnä tietoja rivin sijainnista ja tulostettavan rivin merkkien määrästä. Mutta ennen kuin käskemme käyttöjärjestelmän ydintä suorittamaan osan työstään, meidän on annettava sille hieman lisätietoja. Ensin meidän on kerrottava käyttöjärjestelmän ytimelle, mitä "tiedostokahvaa" tulee käyttää - toisin sanoen mihin tuloste tulee ohjata. Tämä aihe ei kuulu kokoonpanokielen käsikirjan piiriin, joten sanotaan vain, että meidän on käytettävä vakiotulostusvirtaa stdout , joka tarkoittaa: tulosta merkkijono näytölle. Normaali stream Lähtö käyttää kiinteää kahvaa 1, jonka laitamme ebx-rekisteriin.

Olemme nyt erittäin lähellä järjestelmäkutsua, mutta yksi rekisteri on vielä täytettävä. OS-ydin voi suorittaa suuren määrän erilaisia ​​toimintoja, kuten asentaa tiedostojärjestelmiä, lukea tietoja tiedostoista, poistaa tiedostoja ja muita. Vastaavat mekanismit aktivoidaan mainituilla järjestelmäkutsuilla ja ennen kuin siirrämme ohjauksen käyttöjärjestelmän ytimeen, meidän on kerrottava sille, mitä järjestelmäkutsua tulisi käyttää. Sivulta löydät tietoa joistakin järjestelmäkutsuista, ohjelmien käytettävissä- meidän tapauksessamme se on välttämätöntä järjestelmäpuhelu sys_write ("kirjoita tiedot tiedostokuvaajaan") numerolla 4. Joten sijoitamme sen numeron eax-rekisteriin:

Ja se on kaikki! Olemme tehneet kaikki tarvittavat valmistelut järjestelmäkutsun tekemiseksi, joten siirrämme nyt ohjauksen käyttöjärjestelmäytimelle seuraavasti:

Int-käsky tarkoittaa "keskeyttämistä" ja kirjaimellisesti keskeyttää tietyn ohjelman suoritusvirran siirtyen käyttöjärjestelmän ydintilaan. (Tässä tapauksessa sitä käytetään heksadesimaaliarvo 0x80 - sinun ei tarvitse huolehtia siitä toistaiseksi.) Käyttöjärjestelmän ydin tulostaa ecx-rekisterin arvon osoittaman merkkijonon ja palauttaa sitten ohjauksen ohjelmaamme.

Ohjelman suorittamisen lopettamiseksi meidän on tehtävä sys_exit-järjestelmäkutsu, jonka numero on 1. Siksi sijoitamme tämän numeron eax-rekisteriin, keskeytämme ohjelmamme suorituksen uudelleen, minkä jälkeen käyttöjärjestelmäydin lopettaa varovasti suorituksen. ohjelmamme ja palaamme komentotulkin tervehdykseen. Voimme sanoa, että olet suorittanut tehtävän: olet toteuttanut täydellisen (tosin hyvin yksinkertaisen) ohjelman assembly-kielellä, jonka koodi on kehitetty käsin ilman laajoja kirjastoja.

Olemme käsitelleet useita assembly-kielen käytön näkökohtia tässä opetusohjelmassa, ja kuten aiemmin mainittiin, voisimme sen sijaan keskittyä vain teoreettista tietoa. Mutta toivon sitä silti todellinen esimerkki Koit ohjelman hyödylliseksi, ja seuraavassa lehden numerossa käytämme enemmän aikaa käsittelemään joitain tässä oppaassa käsiteltyjä käsitteitä. Lisäksi parannamme ohjelmaamme lisäämällä logiikkaa ja alirutiineja – if- ja goto-lauseiden konekieliversiot.

Kun tutustut tämän ohjelman koodiin, voit yrittää muokata sitä itse suorittaaksesi seuraavat toiminnot:

  • Tulosta erilainen, pidempi merkkijono.
  • Tulosta kaksi riviä peräkkäin.
  • Palauta muokattu sovelluksen poistumiskoodi komentotulkkiin (täytyy käyttää Googlen hakukonetta!).

Jos kohtaat vaikeuksia ja tarvitset apua, vieraile foorumillamme osoitteessa http://forums.linuxvoice.com - oppaan kirjoittaja on lähellä ja opastaa sinua mielellään oikealle tielle. Hyvää ohjelmointia!

Kun kirjoitat ohjelman kokoonpanokielellä, kirjoitat ohjeet prosessorille. Prosessorille annetut komennot ovat yksinkertaisesti koodeja tai opkoodeja tai opkoodeja. Opcodes ovat pohjimmiltaan "luettava teksti" heksadesimaalikoodien versioita. Tämän vuoksi kokoonpanijaa pidetään eniten matalan tason kieli ohjelmointi, kaikki assemblerissä muunnetaan suoraan heksadesimaalikoodit. Toisin sanoen sinulla ei ole kääntäjää, joka muuntaa korkean tason kielen matalan tason kieleksi, kokoaja muuntaa vain kokoonpanokoodit tiedoiksi.

Tässä opetusohjelmassa käsittelemme useita opkoodeja, jotka liittyvät laskemiseen, bittikohtaisiin operaatioihin jne. Muut toimintakoodit: hypätä, vertailla jne. ohjeita käsitellään myöhemmin.

Ohjelmien kommentit jätetään puolipisteen jälkeen. Aivan kuten Delphi tai C kautta //.

Assembly-kielen numerot voidaan esittää binääri-, desimaali- tai heksadesimaalimuodossa. Jotta voit näyttää, missä järjestelmässä numeroa käytetään, sinun on sijoitettava kirjain numeron jälkeen. Binäärijärjestelmässä kirjoitetaan kirjain b (esimerkki: 0000010b, 001011010b), desimaalijärjestelmässä et voi merkitä mitään numeron jälkeen tai merkitä kirjainta d (esimerkit: 4589, 2356d), heksadesimaalijärjestelmä sinun on määritettävä kirjain h, heksadesimaaliluku Alkuun on kirjoitettava nolla (esimerkit: 00889h, 0AC45h, 056Fh, väärin F145Ch, C123h).

Aivan ensimmäinen komento on tunnettu MOV. Tätä komentoa käytetään arvon kopioimiseen (ohita komennon nimi) paikasta toiseen. Tämä "sijainti" voi olla rekisteri, muistipaikka tai välitön arvo (niin kauan kuin alkuperäinen arvo). Komentosyntaksi:

Mov-vastaanotin, lähde

Voit kopioida arvon rekisteristä toiseen.

Mov edx, ecx

Yllä oleva komento kopioi ecx:n sisällön edx:ään. Lähteen ja vastaanottimen koon on oltava sama,

esimerkiksi: tämä komento EI ole kelvollinen:

Mov al, ecx; väärä

Tämä opkoodi yrittää sovittaa DWORD-arvon (32-bittinen) tavuun (8 bittiä). Tätä ei voi tehdä mov-komennolla (tätä varten on muita komentoja).

Ja nämä komennot ovat oikein, koska niiden lähde ja kohde eivät eroa kooltaan:

Mov al, bl mov cl, dl mov cx, dx mov ecx, ebx

Voit myös saada arvon muistista ja tallentaa sen rekisteriin. Otetaan esimerkiksi seuraava muistipiiri:

puolueellisuus34 35 36 37 38 39 3A3B3C3D3E3F40 41 42
tiedot0D0A50 32 44 57 25 7A5E72 EF7DFFILMOITUSC7
(Jokainen lohko edustaa tavua)

Offset-arvo ilmoitetaan tässä tavuna, mutta todellisuudessa se on 32-bittinen arvo. Otetaan esimerkkinä 3A, tämä on myös 32-bittinen arvo: 0000003Ah. Jotkut käyttävät pieniä siirtymiä vain tilan säästämiseksi.

Katso offset 3A yllä olevasta taulukosta. Tämän siirtymän tiedot ovat 25, 7A, 5E, 72, EF jne. Jos haluat esimerkiksi siirtää arvon offsetissa 3A rekisteriin, käytä myös mov-komentoa:

Mov eax, dword ptr

Tarkoitus: sijoita DWORD-kokoinen arvo (32 bittiä) muistista offsetilla 3Ah eax-rekisteriin. Tämän komennon suorittamisen jälkeen eax sisältää arvon 725E7A25h. Olet ehkä huomannut, että tämä on käänteinen muistissa olevalle: 25 7A 5E 72. Tämä johtuu siitä, että arvot tallennetaan muistiin little endian -muodossa. Tämä tarkoittaa, että vähiten merkitsevä tavu tallennetaan merkitsevimpään tavuun: back to front tavujärjestykseen. Luulen, että nämä esimerkit osoittavat sen:

  • dword (32-bittinen) arvo 10203040 heksadesimaali on tallennettu muistiin muodossa: 40, 30, 20, 10
  • sana (16-bittinen) arvo 4050 heksadesimaali tallennetaan muistiin muodossa: 50, 40

Palataanpa yllä olevaan esimerkkiin. Voit tehdä tämän myös muiden kokojen kanssa:

Mov cl, tavu ptr ; cl saa arvon 0Dh mov dx, sana ptr ; dx saa arvon 7DEFh

Olet luultavasti jo ymmärtänyt, että ptr-etuliite tarkoittaa, että sinun on otettava tietty koko muistista. Ja etuliite ennen ptr:tä osoittaa tiedon koon:

Tavu - 1 tavu Word - 2 tavua Dword - 4 tavua

Joskus kokoa ei ole määritetty:

Mov eax,

Koska eax on 32-bittinen rekisteri, kokoaja tietää, että se tarvitsee myös 32-bittisen arvon, tässä tapauksessa muistioffsetista 403045h.

Voit myös käyttää suoria arvoja:

Mov edx, 5006h

Tämä komento kirjoittaa yksinkertaisesti edx-rekisteriin, arvon 5006. Sulkuja [ ja ] käytetään arvon hakemiseen muistista (poikkeama on suluissa), ilman sulkuja se on vain välitön arvo.

Voit myös käyttää rekisteriä muistipaikkana (sen on oltava 32-bittinen 32-bittisissä ohjelmissa):

Mov eax, 403045h; kirjoittaa eax-arvoon 403045 mov cx, ; asettaa arvon ( sanan koko) muistista; määritelty EAX:ssä (403045)

Mov cx:ssä prosessori tarkastelee ensin, mikä arvo (=muistisolu) sisältää eax:n, sitten mikä arvo siinä muistisolussa on ja asettaa sen arvon (sana, 16 bittiä, koska kohde cx on 16-bittinen rekisteröidy) CX:ssä.

Pinotoiminnot - PUSH, POP. Ennen kuin kerroin pinotoiminnoista, selitin sinulle jo, mikä pino on. Pino on muistin alue, johon ESP-pinorekisteri osoittaa. Pino on paikka palautusosoitteiden ja väliaikaisten arvojen tallentamiseen. On olemassa kaksi komentoa arvon työntämiseen pinoon ja sen poistamiseen pinosta: PUSH ja POP. PUSH-komento työntää pinoon arvon, ts. sijoittaa arvon ESP-rekisterin osoittamaan muistipaikkaan, jonka jälkeen ESP-rekisterin arvoa kasvatetaan 4:llä. Pop-käsky ponnahtaa pinosta arvon, ts. ponnahtaa arvon ESP-rekisterin osoittamasta muistipaikasta ja pienentää sitten ESP-rekisterin arvoa 4:llä. Viimeksi pinoon työnnetty arvo pompataan ensin. Kun arvo työnnetään pinoon, pinon osoitin pienenee, ja kun arvoa nostetaan, se kasvaa. Katsotaanpa esimerkkiä:

(1) mov ecx, 100 (2) mov eax, 200 (3) push ecx ; tallenna ecx (4) push eax (5) xor ecx, eax (6) lisää ecx, 400 (7) mov edx, ecx (8) pop ebx (9) pop ecx

  • 1: laita 100 ekx:ään
  • 2: laita 200 eax
  • 3: työnnä arvo ecx:stä (=100) pinoon (työnnä ensin)
  • 4: työnnä arvo eax:sta (=200) pinoon (työntö viimeiseksi)
  • 5/6/7: ecx:n toimintojen suorittaminen, ecx:n arvo muuttuu
  • 8: lisää arvo pinosta ebx:ään: ebx:stä tulee 200 (viimeksi työnnetty, ensimmäinen poksattu)
  • 9: arvon lisääminen pinosta ecx:ään: ecx:stä tulee taas 100 (ensin työnnetty, viimeinen poksattu)

Katso alla olevasta kuvasta, mitä tapahtuu muistissa, kun arvot asetetaan ja poksataan pinoon:

(Tässä pino on täynnä nollia, mutta näin ei todellakaan ole tässä). ESP on siinä paikassa, johon se osoittaa)

Mov ax, 4560h push ax mov cx, FFFFh push cx pop edx edx on nyt 4560FFFFh.

Aliohjelmien kutsuminen ja niistä paluu - CALL, RET. Kutsukomento siirtää ohjauksen lähi- tai etäproseduuriin tallentaen paluupisteen osoitteen pinoon. Ret-komento palauttaa ohjauksen proseduurista kutsuvalle ohjelmalle ja vastaanottaa paluuosoitteen pinosta. Esimerkki:

Koodi.. soita 0455659 ..lisää koodia.. Koodi osoitteesta 455659: add eax, 500 mul eax, edx ret

Kun kutsukomento suoritetaan, prosessori siirtää ohjauksen koodille osoitteessa 455659 ja suorittaa sen ret-komentoon asti ja palauttaa sitten ohjauksen kutsua seuraavaan komentoon. Kutsukomennon kutsumaa koodia kutsutaan toimintosarjaksi. Voit laittaa usein käyttämäsi koodin toimintosarjaan ja kutsua sitä aina, kun tarvitset sitä call-komennolla.

Lisätietoja: Kutsukomento työntää EIP-rekisterin (osoittimen seuraavaan suoritettavaan käskyyn) pinoon, ja ret-komento ponnahtaa sen ja siirtää ohjauksen tähän osoitteeseen. Voit myös määrittää kutsuttavan ohjelman (proseduurin) argumentit. Tämä voidaan tehdä pinon kautta:

Push-arvo_1 push-arvo_2-kutsumenettely

Proseduurin sisällä argumentit voidaan lukea pinosta ja käyttää. Paikalliset muuttujat, ts. Pinoon voidaan myös tallentaa tietoja, joita tarvitaan vain proseduurissa. En mene tähän yksityiskohtiin, koska se voidaan tehdä helposti MASM- ja TASM-kokoonpanoissa. Muista vain, että voit tehdä toimenpiteitä ja että ne voivat käyttää parametreja.

Yksi tärkeä muistiinpano: Eax-rekisteriä käytetään lähes aina toimenpiteen tuloksen tallentamiseen.

Tämä koskee myös Windowsin toimintoja. Voit tietysti käyttää mitä tahansa muuta tapausta omissa menettelyissäsi, mutta tämä on standardi.

Siihen loppuu toinen oppitunti. Seuraavalla oppitunnilla kirjoitamme ensimmäisen ohjelmamme assembly-kielellä.

Takaisin | Sisältö |

Jätä kommentti

Kommentit

pino kasvaa pohjalle ja mitä suurempi se on, sitä pienempi on ESP

Siis jotain tällaista?:
|| kuin tyhjä pino
V
| |ESP
| |6
| |5
| |4
| |3
| |2
| |1
| |0

Koodin jälkeen
paina 0fh
paina 0ffh

|| pinotyyppi
V
|0fh|7
|0ffh|6
| |ESP
| |4
| |3
| |2
| |1
| |0

Jos niin sitten
mitä ESP tarkoittaa, kun pino on tyhjä?