Sukella assembleriin. Täydellinen ohjelmoinnin kurssi Asmassa alkaen ][

Käyttöjärjestelmän käynnistyslatainten, ajurien kirjoittaminen, muistialueiden uudelleenkirjoittaminen ja muut tietokoneen kanssa työskentelyyn liittyvät tehtävät toteutetaan assemblerilla. Valitut assembly-kieltä käsittelevät kirjat auttavat sinua ymmärtämään konesuuntautuneen kielen toimintaperiaatteen ja hallitsemaan sen.

1. Revich Yu – Atmel AVR -mikrokontrollerien käytännön ohjelmointi kokoonpanokielellä, 2014.

"Uutta verta" mikrokontrolleriohjelmoinnin alalla. Atmel AVR:n ominaisuudet on kuvattu yksityiskohtaisesti, siellä on luettelo komennoista ja valmiista resepteistä - kokoonpano ja esimerkkejä. Hyvä asia radioamatööreille ja insinööreille, vaikka se sopii myös aloitteleville koodaajille: AVR MK:n historiaa, perheitä ja ominaisuuksia käsitellään. On syytä huomata, että johdanto on lakoninen ja menee nopeasti asiaan, joten sanoituksesta ei tarvitse valittaa.

2. Kalashnikov O. – Kokoonpanokieli on yksinkertainen. Ohjelmoinnin opettelu, 2011

Todellinen herkku aloittelijoille, jotka vielä googlaavat perusterminologiaa ja etsivät kokoonpanooppikirjaa. Tämä on hän. Kieleen ja ensimmäisiin ohjelmiin tutustumisen lisäksi kosketetaan myös kipukohtia - keskeytyksiä: yksinkertainen asia, mutta aluksi vaikea ymmärtää. Jokaisen luvun myötä assembler-oppitunnit monimutkaistuvat, ja lopussa lukija pystyy kirjoittamaan ohjelmia assemblerissä, optimoimaan niitä, työskentelemään virusten, virustentorjuntaohjelmien, muistin ja tiedostojärjestelmien kanssa.

3. Ablyazov R. – Assembly-kieliohjelmointi x86-64-alustalla, 2011

Painopiste on prosessorin toiminnassa suojatussa tilassa ja pitkässä tilassa. Tämä on välttämätön perusta ohjelmoinnissa Win32:ssa ja Win64:ssä, mikä vaikuttaa assembler-komentoihin, keskeytyksiin, käännös- ja suojamekanismeihin ottaen huomioon tilaerot. Kehitystä harkitaan ikkunallisia sovelluksia ja kuljettajat. Tämä kokoaja Oppikirja sopii aloitteleville koodaajille ja niille, jotka siirtyivät välittömästi assembly-ohjelmointiin, mutta joilla on vähän ymmärrystä x86-64-laitteistoalustasta.

4. Stolyarov A. – Ohjelmointi NASM-kokoonpanokielellä Unix OS:lle, 2011.

Terminologiasta vuorovaikutukseen käyttöjärjestelmän kanssa tämä on liioittelematta yksi parhaista opetusvälineet. Niille, jotka haluavat oppia kokoonpanoohjelmoinnin, mutta eivät halua ylikuormittaa kirjahyllyään, tämä oppikirja riittää. NASM-kokoonpanokielen syntaksia kuvataan yksityiskohtaisesti, rekistereitä ja muistia, vaihtelevan monimutkaisia ​​operaatioita, komentoja käsitellään ja annetaan myös esimerkkejä.

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ämisessä konekielelle. 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 suorituskykyyn. 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ää välittömästi 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 sellaista ohjelmointikieltä, Assembler toimii kaksi kertaa nopeammin ja paremmin. Jotta voisin kirjoittaa siihen helppo ohjelma, se ei vie liikaa aikaa.

Lyhyesti kielen rakenteesta

Jos puhumme yleisesti kielen toiminnasta ja rakenteesta, voimme sanoa varmasti, 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 omansa. Tässä tilanteessa mikä tahansa prosessi, mukaan lukien 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ä. Asentaja vaatii Yksityiskohtainen kuvaus vaadittava komento. Konekomentojen käytön tarpeesta johtuen virheellisten toimien todennäköisyys ja suorituksen monimutkaisuus kasvavat.

Jotta voisi kirjoittaa jopa eniten yksinkertainen ohjelma, ohjelmoijan on oltava pätevä ja hänen tietotasonsa on riittävän korkea. 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 kielellä (Assembler sallii tämän ja selviää hyvin toiminnasta) itse matala taso useimmissa tapauksissa se päättyy onnistuneesti. On parasta käyttää prosessoreita, joilla on rajalliset resurssit. 32-bittiselle tekniikalle annettua kieltä sopii täydellisesti. 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, eroa ei kiitos eri prosessorit, mutta toisen kääntäjän kustannuksella. 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 onkin 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.

Useiden vuosien jälkeen, kun olin tehnyt kaiken ilman menestystä, päätin palata juurille. Ohjelmointiin. Jälleen ottaen huomioon monet "modernit saavutukset" tällä alalla, oli vaikea päättää, mitä todella puuttui, mitä ottaa, jotta se olisi sekä miellyttävää että hyödyllistä. Monia asioita pikkuhiljaa kokeiltuani päätin kuitenkin palata sinne, missä minua veti puoleensa ensimmäisistä tietokonetuttamisen päivistä (jopa Sir Sinclairin luomuksesta) - ohjelmointiin assembly-kielellä. Itse asiassa tunsin aikoinaan assemblerin melko hyvin (in tässä tapauksessa Puhun x86:sta), mutta en ole kirjoittanut siitä mitään lähes 15 vuoteen. Tämä on siis eräänlainen "tuhlaajapojan" paluu.
Mutta tässä odotti ensimmäinen pettymys. Internetistä löytyneet kirjat, käsikirjat ja muut opaskirjat assembleristä sisältävät syvästi pahoitelleni minimitietoa siitä, miten assemblerissä ohjelmoidaan, miksi se on näin ja mitä se antaa.

Esimerkki toiselta alueelta

Jos otamme nyrkkeilyn esimerkkinä, niin kaikki tällaiset käsikirjat opettavat kuinka tehdä lyönti, liikkua lattialla seisten, mutta se, mikä tekee nyrkkeilystä - nyrkkeilyn eikä "sallittua nyrkkeilyä" - puuttuu ehdottomasti. Eli yhdistelmätyötä, renkaan käytön ominaisuuksia, puolustustoimia, taistelun taktista rakennetta ja varsinkin taistelustrategiaa ei oteta huomioon ollenkaan. He opettivat ihmisen lyömään nyrkkeilysäkkiä ja menemään suoraan kehään. Tämä on pohjimmiltaan väärin. Mutta juuri näin on rakennettu lähes kaikki "oppikirjat" ja "oppaat" konekieliohjelmointiin.


Tavallisia kirjoja pitäisi kuitenkin olla, en yksinkertaisesti löytänyt niitä "kuonavuoren" alta. Siksi, ennen kuin täydennämme tietämystä globaalilla kuvauksella arkkitehtuurista, muistotekniikasta ja kaikenlaisista temppuista "kuinka tehdä viikuna kahdesta sormesta", lähestytään kokoonpanokielen ohjelmoinnin kysymystä "ideologisesta" näkökulmasta.

Idylli?

Pieni huomautus, edelleen tekstissä käytetään luokitusta, joka poikkeaa tällä hetkellä yleisestä. Tämä ei kuitenkaan ole syy "kiistoihin totuuden väristä", vaan tässä muodossa on helpompi selittää kirjoittajan näkökulma ohjelmointiin.

Joten tänään näyttää siltä, ​​​​että onnen aikakausi on saapunut ohjelmoijille. Valtava valikoima varoja kaikkiin tilaisuuksiin ja toiveisiin. Täällä on miljoonia "kehyksiä"/"malleja"/"malleja"/"kirjastoja" ja tuhansia työkaluja, jotka "helpottavat ohjelmointia", satoja kieliä ja murteita, kymmeniä menetelmiä ja erilaisia ​​lähestymistapoja ohjelmointiin. Ota se - en halua sitä. Mutta se ei "vie". Ja pointti ei ole uskonnollisissa uskomuksissa, vaan siinä, että se kaikki näyttää yritykseltä syödä jotain mautonta. Jos haluat ja olet ahkera, voit tietysti sopeutua tähän. Mutta palatakseni ohjelmointiin, suurimmassa osassa tarjotusta ei ole teknistä kauneutta - vain paljon "sauvoja" näkyy. Seurauksena on, että näitä "saavutuksia" käytettäessä "taiteilijoiden siveltimen" alta tulee lumoavien maisemien sijaan vankka "abstraktio" tai suosittuja printtejä - jos olet onnekas. Ovatko useimmat ohjelmoijat todella niin keskinkertaisia, tietämättömiä ja heillä on ongelmia geneettisellä tasolla? Ei enpä usko. Joten mikä on syy?
Nykyään ohjelmointiideoita ja tapoja on monia. Katsotaanpa niistä "muodikkaimpia".

  • Pakollinen ohjelmointi - tässä lähestymistavassa ohjelmoija määrittää toimintosarjan, joka johtaa ongelman ratkaisemiseen. Se perustuu ohjelman jakamiseen osiin, jotka suorittavat loogisesti itsenäisiä operaatioita (moduulit, toiminnot, menettelyt). Mutta toisin kuin kirjoitettu lähestymistapa (katso alla), on olemassa tärkeä ominaisuus– muuttujien "kirjoituksen" puute. Toisin sanoen "muuttujatyypin" käsitettä ei ole olemassa, vaan käytetään ymmärrystä, että saman muuttujan arvoilla voi olla eri tyyppejä. Merkittäviä edustajia tätä lähestymistapaa ovat Basic, REXX, MUMPS.
  • Kirjoitettu ohjelmointi - modifiointi pakollinen ohjelmointi kun ohjelmoija ja järjestelmä rajoittavat muuttujien mahdollisia arvoja. Tunnetuimmat kielet ovat Pascal, C.
  • Toiminnallinen ohjelmointi on enemmän matemaattinen menetelmä ongelman ratkaiseminen, kun ratkaisu koostuu funktiohierarkian "rakentamisesta" (ja vastaavasti puuttuvien luomisesta), mikä johtaa ongelman ratkaisuun. Esimerkkejä: Lisp, Forth.
  • Automaattinen ohjelmointi on lähestymistapa, jossa ohjelmoija rakentaa mallin/verkon, joka koostuu objekteista/toimeenpanoelementeistä, jotka vaihtavat viestejä, sekä muuttavat/tallentavat sisäistä "tilaansa" että pystyvät olemaan vuorovaikutuksessa ulkomaailman kanssa. Toisin sanoen tätä kutsutaan yleensä " objektiohjelmointi"(ei oliosuuntautunut). Tämä ohjelmointitapa esitellään Smalltalkissa.
Mutta entä monet muut kielet? Yleensä nämä ovat jo "mutantteja". Esimerkiksi tyyppipohjaisten ja automaattisten lähestymistapojen sekoittaminen tuotti "oliosuuntautuneen ohjelmoinnin".

Kuten näemme, jokainen lähestymistapa (jopa ottamatta huomioon tiettyjen toteutusten rajoituksia) asettaa omat rajoituksensa itse ohjelmointitekniikalle. Mutta toisin ei voi olla. Valitettavasti nämä rajoitukset luodaan usein keinotekoisesti "idean puhtauden säilyttämiseksi". Seurauksena on, että ohjelmoijan on "vääristettävä" alun perin löydetty ratkaisu muotoon, joka ainakin jollain tavalla vastaa käytetyn kielen ideologiaa tai käytettyä "mallia". Tämä on jopa ottamatta huomioon uusia suunnittelu- ja kehitysmenetelmiä ja -menetelmiä.

Vaikuttaa siltä, ​​että ohjelmoiessamme assemblerissä olemme vapaita tekemään mitä tahansa ja miten haluamme ja laitteisto sallii. Mutta heti kun haluamme käyttää " universaali kuljettaja”Kaikkien laitteiden kohdalla meidän on vaihdettava ”luovuuden” vapaus määrättyihin (standardoituihin) lähestymistapoihin ja kuljettajan käyttötapoihin. Heti kun tarvitsimme mahdollisuuden käyttää muiden työtovereiden työtä tai antaa heille mahdollisuuden tehdä samoin oman työmme hedelmillä, meidän on pakko muuttaa ohjelman osien välisen vuorovaikutuksen valinnanvapaus sovituiksi. /standardoidut menetelmät.

Siten se "vapaus", jonka vuoksi ihmiset usein pyrkivät kokoonpanijaksi, osoittautuu usein "myytiks". Ja tähän (rajoitusten ymmärtämiseen ja niiden järjestämiseen) pitäisi mielestäni kiinnittää enemmän huomiota. Ohjelmoijan tulee ymmärtää rajoitusten syy ja se, mikä erottaa konekielisen monista kielistä korkeatasoinen, voi muuttaa niitä tarvittaessa. Assembly-ohjelmoijan on nyt kuitenkin pakko sietää korkean tason kielten asettamia rajoituksia ilman, että niillä ohjelmoivien käytettävissä on "porkkanat". Toisaalta käyttöjärjestelmät tarjoavat monia jo toteutettuja toimintoja, on valmiita kirjastoja ja paljon muuta. Mutta niiden käyttötavat erityistarkoituksena toteutetaan ottamatta huomioon niiden kutsumista kokoonpanokielellä kirjoitetuista ohjelmista ja jopa yleisesti vastoin x86-arkkitehtuurin ohjelmointilogiikkaa. Tämän seurauksena ohjelmointi kokoonpanokielellä ja kutsumalla käyttöjärjestelmän toimintoja tai ulkoisia korkean tason kielikirjastoja on "pelkoa" ja "kauhua".

Mitä pidemmälle metsään, sitä paksumpaa

Joten ymmärsimme, että vaikka kokoaja on hyvin yksinkertainen, sinun on kyettävä käyttämään sitä. Ja tärkein johdonmukaisuus on tarve olla vuorovaikutuksessa sen suoritusympäristön kanssa, jossa ohjelmamme toimii. Jos korkean tason kielten ohjelmoijat pääsevät jo käyttämään tarvittavat kirjastot, toiminnot, alirutiinit moneen otteeseen ja heillä on pääsy tapoihin vuorovaikutuksessa ulkomaailman kanssa kielen idean mukaisessa muodossa, jonka jälkeen ohjelmoijan kokoaja joutuu kahlaamaan läpi kaikenlaisia ​​esteitä. naarmu. Kun katsoo, mitä korkean tason kielet tuottavat käännettäessä, tulee tunne, että kääntäjien kirjoittajilla ei joko ole aavistustakaan, miten x86-arkkitehtuurilla varustettu prosessori toimii, "tai yksi kahdesta" (c).

Otetaan siis järjestyksessä. Ohjelmointi on ennen kaikkea insinöörityötä, eli tieteellistä luovuutta, joka tähtää tehokkaaseen (luotettavuuden, käytettävissä olevien resurssien käytön, toteutusajan ja helppokäyttöisyyden kannalta) ratkaisuun. käytännön ongelmia. Ja kaiken suunnittelun perusta on järjestelmällinen lähestymistapa. Eli mitään ratkaisua ei voida pitää eräänlaisena "jakamattomana" mustana laatikona, joka toimii täydellisessä ja ihanteellisessa tyhjiössä.

Toinen esimerkki toiselta alueelta

Loistavana esimerkkinä järjestelmällinen lähestymistapa Voit mainita kuorma-autojen tuotannon Yhdysvalloissa. Tässä tapauksessa kuorma-auton valmistaja on yksinkertaisesti rungon ja ohjaamon valmistaja + suunnittelijakokooja. Kaikki muu (moottori, vaihteisto, jousitus, sähkölaitteet jne.) hoidetaan asiakkaan toiveiden mukaan. Yksi asiakas halusi hankkia itselleen tietyn Kenworthin moottorilla Detroit Dieselistä, Fuller-manuaalivaihteiston, lehtijousituksen joltain Danalta - kiitos. Tämän asiakkaan ystävä tarvitsi samaa Kenworth-mallia, mutta "natiivi" Paccar-moottorilla, Allison-automaattivaihteistolla ja ilmajousituksella toiselta valmistajalta - helppoa! Ja niin tekevät kaikki kuorma-autojen kokoajat Yhdysvalloissa. Eli kuorma-auto on järjestelmä, jossa jokainen moduuli voidaan korvata toisella samaa tarkoitusta varten ja telakoida saumattomasti olemassa oleviin. Lisäksi moduulien telakointimenetelmä on tehty mahdollisimman monipuolisesti ja kätevästi lisälaajennus toiminnallisuus. Tähän insinöörin tulee pyrkiä.

Valitettavasti joudumme elämään sen kanssa, mitä meillä on, mutta tulevaisuudessa sitä tulisi välttää. Joten ohjelma on pohjimmiltaan joukko moduuleja (ei ole väliä miksi niitä kutsutaan tai miten ne "käyttäytyvät"), jonka muodostamalla saavutamme ratkaisun käsillä olevaan ongelmaan. Tehokkuuden vuoksi on erittäin toivottavaa, että näitä moduuleja voidaan käyttää uudelleen. Eikä vain käyttää hinnalla millä hyvänsä, vaan käyttää kätevällä tavalla. Ja tässä meitä odottaa toinen epämiellyttävä "yllätys". Useimmat korkean tason kielet toimivat sellaisilla rakenneyksiköillä kuin "toiminto" ja "menettely". Ja tapana olla vuorovaikutuksessa heidän kanssaan käytetään "parametrien ohittamista". Tämä on varsin loogista, eikä tässä herää kysymyksiä. Mutta kuten aina, "tärkeää ei ole se, mitä on tehty, vaan miten se tehdään" (c). Ja tästä alkaa käsittämättömin osa. Nykyään on kolme yleistä tapaa järjestää parametrien siirto: cdecl, stdcall, pikapuhelu. Joten mikään näistä menetelmistä ei ole "natiivi" x86:lle. Lisäksi ne kaikki ovat virheellisiä kutsuttujen aliohjelmien toiminnallisuuden laajentamisen kannalta. Eli lisäämällä välitettyjen parametrien määrää joudumme muuttamaan tämän funktion/aliohjelman kaikkia kutsupisteitä tai luomaan uuden aliohjelman, jolla on samanlainen toiminnallisuus ja jota kutsutaan hieman eri tavalla.

Yllä olevat menetelmät parametrien välittämiseksi toimivat suhteellisen hyvin prosessoreissa, joissa on 2 erillistä pinoa (tietopino ja osoite/ohjauspino) ja kehitetyt pinonkäsittelykomennot (ainakin indeksipääsy pinoelementteihin). Mutta kun ohjelmoit x86:lla, sinun täytyy ensin vääristää parametreja välitettäessä/vastaanottaessa ja sitten muistaa "rakenteellisesti" poistaa ne pinosta. Samalla yritetään arvata/laskea pinon enimmäissyvyyttä. Muistakaamme, että x86 (16/32-bittinen tila) on prosessori, jossa on:

  • erikoisrekisterit (RON:t - yleiskäyttöiset rekisterit - puuttuvat sellaisenaan: eli emme voi yhdellä komennolla kertoa GS-rekisterin sisältöä EDI:n arvolla ja saada tulosta EDX:ECX-parissa tai jakaa sisältörekisterin EAX arvo EDI:ESI-rekisteriparista);
  • rekistereitä on vähän;
  • yksi pino;
  • muistipaikka ei anna mitään tietoa sinne tallennetun arvon tyypistä.
Toisin sanoen ohjelmointitekniikat, joita käytetään prosessoreissa, joissa on suuri rekisteritiedosto, tuki useille itsenäisille pinoille jne. Useimmiten ei sovellu ohjelmoitaessa x86:lle.

Seuraava vuorovaikutuksen ominaisuus "korkeatasoisilla kielillä" kirjoitettujen valmiiden moduulien kanssa on "taistelu" "muuttujatyyppien" kanssa. Toisaalta syy muuttujatyyppien esiintymiseen on selvä - ohjelmoija tietää, mitä arvoja hänen aliohjelmansa / moduulinsa sisällä käytetään. Tämän perusteella vaikuttaa varsin loogiselta, että asettamalla muuttujan arvojen tyyppi, voimme "yksinkertaistaa" ohjelman kirjoittamista uskomalla tyyppien/arvorajojen hallinnan kielenkääntäjälle. Mutta täälläkin vauva heitettiin ulos kylpyveden mukana. Koska mikä tahansa ohjelma ei ole kirjoitettu luomaan pallomaisia ​​hevosia tyhjiössä, vaan niin käytännön työ käyttäjätietojen kanssa. Eli ilmeinen rikkomus järjestelmälähestymistapaa kohtaan - ikään kuin korkean tason kielten kehittäjät harkitsivat järjestelmiään ottamatta huomioon vuorovaikutusta ulkomaailman kanssa. Tästä johtuen kirjoitetulla kielellä ohjelmoiessaan kehittäjän on ennakoitava kaikki mahdolliset "väärät" syöttötiedot ja etsittävä keinoja kiertää epävarmuustekijät. Ja tässä hirveät tukijärjestelmät tulevat peliin. säännöllisiä lausekkeita, käsittely poikkeuksellisissa tilanteissa, menetelmän/menettelyn allekirjoitukset erilaisia ​​tyyppejä arvot ja muun sukupolven kainalosauvat.

Kuten edellä mainittiin, x86-arkkitehtuurissa itse muistisoluun tallennetulla arvolla ei ole minkäänlaista tyyppiä. Assembler-ohjelmoija saa etuoikeuden ja vastuuta määrittääkseen, kuinka tämä arvo käsitellään. Mitä tulee arvon tyypin määrittämiseen ja sen käsittelyyn, on monia vaihtoehtoja, joista valita. Mutta korostetaan vielä kerran, että ne kaikki liittyvät vain käyttäjältä saamiin arvoihin. Kuten kirjoitettujen kielten kehittäjät totesivat oikein: sisäisten ja palvelumuuttujien arvojen tyypit ovat melkein aina tiedossa etukäteen.

Tämä syy (parametrien vääristynyt siirtäminen korkean tason kielillä kirjoitettuihin moduuleihin ja tarve tarkkailla samoille moduuleille siirrettyjen parametrien tyyppejä) näyttää olevan tärkein syy siihen, miksi ohjelmointi kokoonpanokielellä on kohtuuttoman vaikeaa. Ja enemmistö mieluummin ymmärtää "korkean tason kielten" viidakon hyödyntääkseen sitä, mitä muut ovat jo kehittäneet, sen sijaan, että kärsisivät ja laittaisivat samat "standardi" kainalosauvat korjaamaan sitä, mitä he eivät tehneet. Ja se on harvinainen assembler-kääntäjä, joka jollakin tavalla "vapauttaa" ohjelmoijan tästä rutiinista.

Mitä tehdä?

Alustavat johtopäätökset ottaen huomioon 15 vuotta tauko assembly-ohjelmointiin.
Ensinnäkin moduuleista tai ohjelman osista. Yleisesti ottaen on syytä erottaa kaksi tyyppistä ohjelman executive-moduulia kokoonpanokielellä - "toiminta" ja "alirutiini".
  • "Operaatio" on moduuli, joka suorittaa "atomi"-toiminnon ja ei vaadi monia parametreja sen suorittamiseen (esimerkiksi koko näytön tyhjennystoiminto tai mediaanin laskentatoiminto numerosarja ja niin edelleen.).
  • "Alirutiinia" tulee kutsua toiminnalliseksi moduuliksi, joka vaatii toimiakseen monia syöttöparametreja (yli 2x-3x).
Ja tässä kannattaa arvioida kokemusta pakollisesta ja toiminnallisia kieliä. He antoivat meille 2 arvokasta työkalua, joita kannattaa käyttää: "tietorakenne" (tai REXX-esimerkiksi yhdistetyt/lisättävät muuttujat) ja "datan muuttumattomuus".

On myös hyödyllistä noudattaa muuttumattomuuden sääntöä - eli ohitettujen parametrien muuttumattomuutta. Aliohjelma ei voi (ei pitäisi) muuttaa sille välitetyn rakenteen arvoja ja tulos palautetaan joko rekistereissä (enintään 2-3 parametria) tai myös uudessa luotavassa rakenteessa. Näin vapaudumme tarpeesta tehdä kopioita rakenteista aliohjelmien "unohtuneiden" datamuutosten yhteydessä ja voimme käyttää jo luotua rakennetta kokonaan tai sen pääosaa useiden samalla/samanlaisella parametrijoukolla toimivien aliohjelmien kutsumiseen. . Lisäksi lähes automaattisesti pääsemme seuraavaan "toiminnalliseen" sääntöön - aliohjelmien ja toimintojen sisäiseen kontekstiriippumattomuuteen. Toisin sanoen tilan/datan erottamiseen niiden käsittelymenetelmästä/alirutiinista (toisin kuin automaatiomallissa). Tapauksissa rinnakkaisohjelmointi, ja jakaminen Yhtä aliohjelmaa käyttämällä pääsemme eroon tarpeesta luoda useita suorituskonteksteja ja valvoa niiden "ei-leikkauskohtaa" sekä siitä, että yhdestä aliohjelmasta luodaan useita esiintymiä eri "tiloilla" useiden kutsujen tapauksessa.

Tietojen "tyypeistä" tässä voit joko jättää "kaikki sellaisenaan" tai et voi myöskään keksiä pyörää uudelleen ja käyttää sitä, mitä pakollisten kielten kääntäjien kehittäjät ovat pitkään käyttäneet - "arvotyypin tunnistetta". Eli kaikki tiedot tulevat ulkopuolinen maailma analysoidaan ja jokaiselle tuloksena olevalle arvolle määritetään käsiteltävän tyypin tunniste (kokonaisluku, kelluva, pakattu BCD, merkkikoodi jne.) ja kentän/arvon koko. Näiden tietojen hallussa ohjelmoija toisaalta ei pakota käyttäjää tarpeettoman kapeaan arvojen syöttämisen "sääntöjen" kehykseen, ja toisaalta hänellä on mahdollisuus valita tehokkain tapa käsitellä käyttäjän tietoja. työprosessin aikana. Mutta toistan vielä kerran, tämä koskee vain käyttäjätietojen käsittelyä.

Nämä olivat yleisiä huomioita Assembly-ohjelmoinnista, joka ei liity suunnitteluun, virheenkorjaukseen ja virheiden käsittelyyn. Toivon, että käyttöjärjestelmäkehittäjillä, jotka kirjoittavat niitä tyhjästä (ja vielä enemmän assemblerissä), on ajattelemisen aihetta ja he valitsevat (vaikka eivät yllä kuvatut, mutta mitä tahansa muita) tapoja tehdä ohjelmoinnista assemblerissä järjestelmällisempää, kätevämpää. ja nautinnollista, eivätkä he sokeasti kopioi muiden ihmisten, usein toivottoman "kieroja" vaihtoehtoja.

Nykyään on olemassa valtava määrä korkean tason ohjelmointikieliä. Heidän taustaansa vasten ohjelmointi sisään matalan tason kieli- kokoaja - voi ensi silmäyksellä vaikuttaa vanhentuneelta ja järjettömältä. Siltä se kuitenkin vain näyttää. On tunnustettava, että assembler on itse asiassa prosessorikieli, mikä tarkoittaa, että sitä ei voida tehdä ilman sitä niin kauan kuin prosessorit ovat olemassa. Assembly-ohjelmoinnin tärkeimmät edut ovat maksimi suorituskyky ja vastaanotettujen ohjelmien vähimmäiskoko.

Haitat johtuvat usein vain taipumuksesta nykyaikaiset markkinat mieluummin määrää kuin laatua. Nykyaikaiset tietokoneet pystyvät helposti selviytymään joukosta korkean tason toimintojen komentoja, ja jos se ei ole helppoa, päivitä koneesi laitteisto! Tämä on kaupallisen ohjelmoinnin laki. Jos me puhumme sielun ohjelmoinnista, niin kompakti ja ketterä assemblykielellä kirjoitettu ohjelma jättää paljon miellyttävämmän vaikutelman kuin korkean tason räjähdys, joka on kuormitettu joukolla turhia operaatioita. On olemassa mielipide, että vain harvat voivat ohjelmoida assemblerissä. Se ei ole totta. Tietysti lahjakkaat kokoonpano-ohjelmoijat voidaan laskea yhdellä kädellä, mutta näin on lähes kaikilla ihmisen toiminnan alueella. Ässäkuljettajia ei ole paljon, mutta kuka tahansa voi oppia ajamaan autoa, jos haluaa. Tämän artikkelisarjan lukemisen jälkeen sinusta ei tule siistiä hakkeria. Saat kuitenkin yleistä tietoa ja oppia yksinkertaisia ​​tapoja asennuskieliohjelmointi Windowsille käyttämällä sen sisäänrakennettuja toimintoja ja kääntäjämakroohjeita. Luonnollisesti, jotta voit hallita Windows-ohjelmointia, sinulla on oltava Windows-taitoja ja -kokemusta. Aluksi et ymmärrä paljon, mutta älä järkytä tästä ja lue: ajan myötä kaikki loksahtaa paikoilleen.

Joten ohjelmoinnin aloittamiseksi tarvitsemme ainakin kääntäjän. Kääntäjä on ohjelma, joka kääntää ohjelmoijan kirjoittaman lähdekoodin prosessorin suoritettavaksi. konekoodi. Useimmat assembler-oppikirjat keskittyvät MASM32-paketin (Microsoft Macro Assembler) käyttöön. Mutta monipuolisuutena ja useista muista syistä esittelen teille nuoren kääntäjän FASM:n (Flat Assembler), joka on nopeasti kasvattamassa suosiota. Tämä kääntäjä on melko helppo asentaa ja käyttää, se on kompakti ja nopea, siinä on rikas ja tilava makrosyntaksi, jonka avulla voit automatisoida monia rutiinitehtävät. Hänen uusin versio voit ladata osoitteesta: verkkosivuilla valitsemalla flat assembler Windowsille. Asenna FASM luomalla kansio, esimerkiksi "D:\FASM" ja purkamalla ladatun zip-arkiston sisältö siihen. Suorita FASMW.EXE ja sulje muuttamatta mitään. Muuten, jos käytät standardi johdin, ja tiedostotunniste (esimerkiksi .EXE) ei näy, suosittelen, että suoritat Työkalut -> Kansion asetukset -> Näytä ja poistat Piilota laajennukset rekisteröityjen tiedostotyyppien kohdalla. Kääntäjän ensimmäisen käynnistyksen jälkeen kansiossamme pitäisi näkyä asetustiedosto - FASMW.INI. Avaa se tavallisella muistilehtiöllä ja lisää 3 riviä alareunaan:

Fasminc=D:\FASM\INCLUDE
Include=D:\FASM\INCLUDE

Jos purit FASM:n toiseen paikkaan, korvaa "D:\FASM\" polullasi. Tallenna ja sulje FASMW.INI. Tulevaisuudessa selitän lyhyesti, kuinka käytämme kääntäjää:
1. Kirjoitamme ohjelman tekstiä tai avaamme aiemmin kirjoitettua .asm-tiedostoon tallennettua tekstiä tai liitämme ohjelman tekstin leikepöydältä yhdistelmällä.
2. Paina F9 kääntääksesi ja ajaaksesi ohjelman tai Ctrl+F9 vain kääntääksesi. Jos ohjelman tekstiä ei ole vielä tallennettu, kääntäjä pyytää sinua tallentamaan sen ennen kääntämistä.
3. Jos ohjelma käynnistyy, testaamme sen toimivuutta, jos ei, etsimme virheitä, joista vakavimmat kääntäjä osoittaa meille tai vihjaa hienovaraisesti.
No, nyt voimme aloittaa kauan odotetun harjoituksen. Käynnistämme FASMW.EXE-tiedoston ja kirjoitamme siihen ensimmäisen ohjelmamme koodin:

Sisällytä "%fasminc%/win32ax.inc"

Data
Kuvateksti db "Ensimmäinen ohjelmani.",0
Teksti db "Hei kaikille!",0

Koodi
alkaa:

kutsua ExitProcess,0

Napsauta Suorita -> Suorita tai näppäimistöltä F9. Määritä tallennusikkunassa tallennettavan tiedoston nimi ja kansio. On suositeltavaa tottua tapana tallentaa jokainen ohjelma sisään erillinen kansio, jotta et joutuisi hämmennyksiin tulevaisuudessa, kun jokaisessa ohjelmassa voi olla joukko tiedostoja: kuvia, kuvakkeita, musiikkia jne. Jos kääntäjä tuottaa virheen, tarkista huolellisesti sen määrittämä rivi - ehkä et unohda pilkkua tai välilyöntiä. Sinun on myös tiedettävä, että kääntäjä on isot ja pienet kirjaimet erotteleva, joten .data ja .data käsitellään kahtena erilaisia ​​ohjeita. Jos teit kaiken oikein, tuloksena on yksinkertainen viestilaatikko (kuva 1). Selvitetään nyt, mitä kirjoitimme ohjelman tekstiin. Ensimmäisellä rivillä sisällytimme ohjelmaamme suuren tekstin useista tiedostoista. Muistatko, että asennuksen aikana kirjoitimme 3 riviä FASMO ini-tiedostoon? Nyt %fasminc% ohjelmatekstissä tarkoittaa D:\FASM\INCLUDE tai määrittämääsi polkua. Sisällytä-direktiivi näyttää lisäävän kohtaan määrätty paikka tekstiä toisesta tiedostosta. Avaa WIN32AX.INC-tiedosto include-kansiossa notepadilla tai itse FASMAssa ja varmista, että olemme automaattisesti lisänneet (liittäneet) ohjelmaamme myös tekstin osoitteesta win32a.inc, macro/if.inc, joukon käsittämättömiä (esim. nyt) makroohjeet ja yleinen joukko Windowsin funktiokirjastoja. Jokainen mukana olevista tiedostoista voi puolestaan ​​sisältää useita muita mukana olevia tiedostoja, ja tämä ketju voi mennä horisontin ulkopuolelle. Mukana olevien tiedostojen avulla järjestämme eräänlaisen korkean tason kielen: välttääksemme jokaisen funktion manuaalisen kuvauksen rutiinia sisällytämme kokonaisia ​​kuvauskirjastoja vakio-ominaisuudet Windows. Onko tämä kaikki todella tarpeellista näin pienelle ohjelmalle? Ei, tämä on jotain "herrasmiessettiä kaikkiin tilanteisiin". Oikeat hakkerit eivät tietenkään yhdistä kaikkea, mutta olemme vasta oppimassa, joten on anteeksiantavaa, että teemme tämän ensimmäistä kertaa.

Seuraavaksi meillä on tietoosio nimetty - .data. Tässä osiossa määritetään kaksi muuttujaa - kuvateksti ja teksti. Nämä eivät ole erikoiskomentoja, joten niiden nimiä voidaan muuttaa haluamallasi tavalla, jopa a ja b, kunhan ei ole välilyöntejä eikä venäjäksi. No, et voi nimetä muuttujia varatut sanat, esimerkiksi koodi tai data, mutta voit käyttää koodia_ tai data1. db-komento tarkoittaa "määrittele tavu". Kaikki tämä teksti ei tietenkään mahdu yhteen tavuun, koska jokainen yksittäinen merkki vie kokonaisen tavun. Mutta tässä tapauksessa tällä komennolla määritämme vain osoitinmuuttujan. Se sisältää osoitteen, johon merkkijonon ensimmäinen merkki on tallennettu. Rivin teksti ilmoitetaan lainausmerkeissä, ja voit halutessasi laittaa sekä "sellainen" että "sellainen" lainausmerkkeihin - kunhan aloituslainausmerkki on sama kuin lopun lainausmerkki. Pilkun jälkeinen nolla lisää merkkijonon loppuun nollatavun, joka osoittaa merkkijonon loppua (nolla-pääte). Yritä poistaa tämä nolla ja pilkku ensimmäiseltä riviltä ja katso mitä saat. Tämän tietyn esimerkin toisella rivillä voit tehdä ilman nollaa (poista se pilkun kanssa - muuten kääntäjä ilmoittaa virheestä), mutta tämä toimii vain, koska esimerkissämme seuraava osa alkaa heti toisen jälkeen. riville, ja ennen kuin se alkaa, kääntäjä syöttää automaattisesti joukon nollia, jotka kohdistavat edellisen osan. Yleensä nollia lopussa tekstijonoja edellytetään! Seuraava osa - jakso suoritettava koodi ohjelmat - .koodi. Osion alussa on alku: etiketti. Se tarkoittaa, että tästä pisteestä lähtien ohjelmamme alkaa suorittaa. Ensimmäinen komento on kutsu makrokäsky. Se kutsuu sisäänrakennettua Windows API -toimintoa MessageBox. API-toiminnot (sovellusohjelmointirajapinta) yksinkertaistavat merkittävästi työskentelyä käyttöjärjestelmässä. On kuin pyytäisimme käyttöjärjestelmää suorittamaan jonkin vakiotoiminnon, ja se suorittaa sen ja palauttaa meille tehdyn työn tuloksen. Toiminnon nimeä seuraa sen parametrit pilkuilla erotettuna. MessageBox-toiminnolla on seuraavat parametrit:

Ensimmäisen parametrin on sisällettävä omistajaikkunan kahva. Kahva on jotain sellaista henkilökohtainen numero, joka myönnetään käyttöjärjestelmä jokainen objekti (prosessi, ikkuna jne.). Esimerkissämme 0 tarkoittaa, että ikkunalla ei ole omistajaa, se on oma ja ei ole riippuvainen muista ikkunoista.
2. parametri on osoitin viestin tekstin ensimmäisen kirjaimen osoitteeseen, joka päättyy yllä mainittuun nollapäätteeseen. Ymmärtääksemme selvästi, että tämä on vain osoite, siirretään tätä osoitetta 2 tavulla suoraan funktiokutsussa: kutsu MessageBox,0,Teksti+2,Caption,MB_OK ja varmista, että nyt teksti näkyy ilman kahta ensimmäistä kirjainta .
3. - viestin otsikon ensimmäisen kirjaimen osoiteilmaisin.
4. - viestin tyyli. Löydät luettelon näistä tyyleistä esimerkiksi hakemistosta INCLUDE\EQUATES\USER32.INC. Tätä varten sinun olisi parempi käyttää Notepad-hakua löytääksesi nopeasti MB_OK ja muut. Valitettavasti siellä ei ole kuvausta, mutta tyylin nimestä voit yleensä arvata sen tarkoituksen. Muuten, kaikki nämä tyylit voidaan korvata numerolla, joka tarkoittaa yhtä tyyliä tai niiden yhdistelmää, esimerkiksi: MB_OK + MB_ICONEXCLAMATION. USER32.INC määrittää heksadesimaaliarvot. Voit käyttää niitä sellaisenaan tai muuntaa ne sellaisiksi desimaalijärjestelmä V suunnittelutila standardi Windows-laskin. Jos et ole perehtynyt numerojärjestelmiin etkä tiedä miten desimaali eroaa heksadesimaalista, sinulla on 2 vaihtoehtoa: joko lue tämä asia itse netistä/oppikirjasta/kysy ystävältä tai jätä tämä idea parempiin aikoihin ja yritä tehdä ilman tätä tietoa. Tässä en anna edes lyhyitä tietoja numerojärjestelmistä, koska jopa ilman minua on niistä kirjoitettu valtava määrä artikkeleita ja sivuja, joilla on ajateltavissa oleva taso.

Palataan lampaidemme luo. Joitakin tyylejä ei voi käyttää samanaikaisesti – esimerkiksi MB_OKCANCEL ja MB_YESNO. Syynä on niiden summa numeerisia arvoja(1+4=5) vastaa toisen tyylin arvoa - MB_RETRYCANCEL. Kokeile nyt toimintoparametreja harjoitellaksesi materiaalin kiinnittämistä, ja siirrymme eteenpäin. MessageBox-toiminto keskeyttää ohjelman suorittamisen ja odottaa käyttäjän toimia. Kun toiminto on valmis, toiminto palauttaa käyttäjän toiminnan tuloksen ohjelmaan ja ohjelman suoritus jatkuu. ExitProcess-funktion kutsuminen lopettaa ohjelmamme prosessin. Tällä toiminnolla on vain yksi parametri - poistumiskoodi. Yleensä, jos ohjelma poistuu normaalisti, tämä koodi yhtä suuri kuin nolla. Ymmärtääkseen paremmin viimeinen rivi koodimme - .end start, - tutki huolellisesti vastaava koodi: muoto PE GUI 4.0

sisältää "%fasminc%/win32a.inc"

osio ".data" data luettavissa kirjoitettava

Kuvateksti db "Ensimmäinen ohjelmamme.",0
Teksti db "FASM-kokoonpano on helppoa!",0

osio ".code" koodi luettavissa suoritettava
alkaa:
kutsu MessageBox,0,Teksti,Teksti,MB_OK
kutsua ExitProcess,0

osio ".idata" tuoda tiedot luettavissa kirjoitettava
kirjasto KERNEL32, "KERNEL32.DLL",\
KÄYTTÄJÄ32, "USER32.DLL"

tuonti KERNEL32,\
ExitProcess, "ExitProcess"

tuo USER32,\
MessageBox, "MessageBoxA"

Kääntäjälle se on lähes identtinen edellisen esimerkin kanssa, mutta meille tämä teksti näyttää erilaiselta ohjelmalta. Annoin nimenomaan tämän toisen esimerkin, jotta saat heti alussa käsityksen makrokäskyjen käytöstä ja tästä lähtien voit siirtyä yhdistetystä tiedostosta toiseen itsenäisesti päästä ohjelman alle piilotettuun todelliseen koodiin. makrojen verho. Yritetään ymmärtää erot. Aivan ensimmäinen, ei kovin havaittavissa, mutta sen arvoinen erityistä huomiota- tämä on se, mitä yhdistämme ohjelmatekstiin, ei win32ax, vaan vain win32a. Hylkäsimme suuren sarjan ja rajoittuimme pieneen. Yritämme olla yhdistämättä kaikkea win32axista, vaikka tarvitsemmekin sitä vielä toistaiseksi. Siksi win32ax:n makrojen mukaan kirjoitamme manuaalisesti joitakin määritelmiä. Esimerkiksi makro win32ax-tiedostosta:
makro .data ( osio ".data" data luettavissa kirjoitettava )

kääntämisen aikana, korvaa automaattisesti .data-osion ".data" tiedot luettavissa ja kirjoitettavissa. Koska emme ole sisällyttäneet tätä makroa ohjelman tekstiin, meidän on kirjoitettava se itse yksityiskohtainen määritelmä osiot. Analogisesti voit löytää syyt jäljellä oleviin muutoksiin toisen esimerkin ohjelmatekstistä. Makrot auttavat sinua välttämään kirjoitusrutiineja suuria ohjelmia. Siksi sinun täytyy vain tottua niihin heti, ja tulet rakastamaan niitä myöhemmin =). Yritä itse selvittää erot ensimmäisen ja toisen esimerkin välillä käyttämällä win32ax:ssa käytettyjen makrojen tekstiä. Sanon vain, että voit määrittää minkä tahansa muun datan tai koodiosan nimen lainausmerkeissä - esimerkiksi: jakso "virus" koodi luettavissa oleva suoritettava tiedosto. Tämä on vain osion nimi, eikä se ole komento tai käsky. Jos ymmärrät kaiken, voit jo kirjoittaa oman viruksen. Usko minua, se on erittäin helppoa. Vaihda vain viestin otsikko ja teksti:
Kuvateksti db "Vaarallinen virus.",0

Teksti db "Hei, olen erityisen vaarallinen troijalainen virus ja levitän Internetissä.",13,\
"Koska kirjoittajani ei osaa kirjoittaa haittaa aiheuttavia viruksia, sinun on autettava minua."13,\
"Ole hyvä ja toimi seuraavasti:",13,\
"1. Tyhjennä C:\Windows- ja C:\Program files -hakemistot levyltäsi",13,\
"2.Lähetä tämä tiedosto kaikille ystävillesi",13,\
"Kiitos etukäteen.",0

Numero 13 on Microsoft-järjestelmien rivinvaihtomerkin koodi. \-merkkiä käytetään FASM-syntaksissa useiden rivien yhdistämiseen yhdeksi ilman sitä, rivi olisi liian pitkä ja menisi pois näytön reunasta. Voimme esimerkiksi kirjoittaa start:, tai voimme myös kirjoittaa st\
ar\
t:

Kääntäjä ei huomaa eroa ensimmäisen ja toisen vaihtoehdon välillä.
Tehdäksesi "viruksestamme" vielä hauskempaa, voit korvata MB_OK:lla MB_ICONHAND tai yksinkertaisesti numerolla 16. Tässä tapauksessa ikkuna on virheilmoituksen tyylinen ja se tuottaa vaikuttavamman vaikutuksen uhriin. "infektio" (kuva 2).

Siinä kaikki tältä päivältä. Toivotan menestystä ja nähdään taas!
Kaikki annetut esimerkit on testattu toimimaan oikein Windows XP:ssä ja toimivat todennäköisesti myös muissa Windows-versioissa, mutta en takaa, että ne toimivat oikein tietokoneessasi. Lähdetekstit foorumilta löytyvät ohjelmat.

Assembly-kieliohjelmointi

Tämä osa kurssista kattaa asennuskieliohjelmoinnin perusteet Win32-arkkitehtuurille.

Kaikki koneen prosessit alimmalla laitteistotasolla ohjataan vain komennoilla (käskyillä) konekieli. Assembly-kieli on konekielen symbolinen esitys. Kokoonpanokielen avulla voit kirjoittaa lyhyitä ja nopeat ohjelmat. Tämä prosessi on kuitenkin erittäin työvoimavaltainen. Kirjoittamaan niin paljon kuin mahdollista tehokas ohjelma tarpeellista hyvä tieto kokoonpanokielen komentojen ominaisuudet, tarkkaavaisuus ja tarkkuus. Siksi todellisuudessa pääasiassa ohjelmat kirjoitetaan kokoonpanokielellä, jonka pitäisi tarjota tehokasta työtä laitteiston kanssa. Myös ohjelman osat, jotka ovat kriittisiä suoritusajan tai muistin kulutuksen kannalta, kirjoitetaan kokoonpanokielellä. Myöhemmin ne formalisoidaan aliohjelmien muodossa ja yhdistetään korkean tason kielen koodiin.

1. Rekisterit

Rekisterit ovat erityisiä muistisoluja, jotka sijaitsevat suoraan prosessorissa. Rekistereiden kanssa työskentely on paljon nopeampaa kuin solujen kanssa RAM-muisti Siksi rekistereitä käytetään aktiivisesti sekä kokoonpanokielisissä ohjelmissa että korkean tason kielenkääntäjissä.

Rekisterit voidaan jakaa yleiskäyttöiset rekisterit,komentoindeksi,lippurekisterit ja segmenttirekisterit.

1.1. Yleiskäyttöiset rekisterit

TO Yleiskäyttöiset rekisterit ovat 8 rekisterin ryhmä, joita voidaan käyttää konekieliohjelmassa. Kaikki rekisterit ovat kooltaan 32 bittiä ja ne voidaan jakaa kahteen tai useampaan osaan.

Kuten kuvasta näkyy, ESI-, EDI-, ESP- ja EBP-rekisterien avulla voit käyttää alempia 16 bittiä nimillä SI, DI, SP ja BP, ja EAX-, EBX-, ECX- ja EDX-rekistereillä päästä sekä alempaan 16 bittiin (nimillä AX , BX, CX ja DX) että kahteen alempaa tavuun erikseen (nimeltään AH/AL, BH/BL, CH/CL ja

Rekisterien nimet tulevat niiden tarkoituksesta:

EAX/AX/AH/AL (akkurekisteri) – paristo;

EBX/BX/BH/BL (perusrekisteri) – perusrekisteri;

ECX/CX/CH/CL (laskurirekisteri) – laskuri;

EDX/DX/DH/DL (tietorekisteri) – tietorekisteri;

ESI/SI (lähde hakemistorekisteri) – lähdeindeksi;

EDI/DI (destination index register) – vastaanottajan (vastaanottajan) indeksi;

ESP/SP (pinoosoitinrekisteri) – pinoosoitinrekisteri;

EBP/BP (base pointer register) – pinokehyksen perusosoitinrekisteri.

Nykyisestä erikoistumisesta huolimatta kaikkia rekistereitä voidaan käyttää missä tahansa konetoiminnassa. On kuitenkin otettava huomioon, että jotkut ohjeet toimivat vain tiettyjen rekisterien kanssa. Esimerkiksi kerto- ja jakokäskyt käyttävät EAX- ja EDX-rekistereitä lähdetietojen ja operaation tuloksen tallentamiseen. Silmukkaohjauskäskyt käyttävät ECX-rekisteriä silmukkalaskurina.

Toinen vivahde on käyttää rekistereitä pohjana, ts. RAM-osoitteen tallennus. Perusrekistereinä voidaan käyttää mitä tahansa rekistereitä, mutta on suositeltavaa käyttää EBX-, ESI-, EDI- tai EBP-rekistereitä. Tässä tapauksessa konekäskyn koko on yleensä pienempi.

Valitettavasti rekistereiden määrä on katastrofaalisen pieni, ja usein on vaikea määrittää, miten niitä optimaalisesti käytetään.

1.2. Komentoindeksi

EIP-rekisteri ( komentoindeksi) sisältää seuraavan suoritettavan komennon siirtymän. Tämä rekisteri ei ole suoraan ohjelmoijan käytettävissä, mutta sen arvoa ladataan ja muutetaan erilaisilla ohjauskomennoilla, jotka sisältävät komennot ehdollisiin ja ehdottomiin hyppyihin, proseduurien kutsumiseen ja toimenpiteistä paluuun.

1.3. Lippurekisteri

Lippu on bitti, joka saa arvon 1 ("lippu asetettu"), jos jokin ehto täyttyy, ja arvon 0 ("lippu tyhjennetty") muussa tapauksessa. Prosessorissa on lippurekisteri, joka sisältää joukon lippuja, jotka kuvastavat prosessorin nykyistä tilaa.

Nimitys

Nimi

Lippu siirretty

Varattu

Pariteetin lippu

Varattu

Ylimääräinen kantolippu

Ylimääräinen

Varattu

Nolla lippu

Lipun merkki

Lipun jäljitin

Keskeytä käyttöön -lippu

Lupa lippu

Merkitse ohjeet

Repo lippu

I/O-oikeustaso

Taso klo

Lippu sisäkkäin

Varattu

Lippua jatkettiin

Virtuaalinen-8086-tila

Virtuaalinen tila

Tarkistaa sinua

Virtuaalinen keskeytyslippu

Virtuaalinen

Virtuaalinen keskeytys odottaa

Odottaa

Tarkistaa

Varattu

Lippujen CF, DF ja IF arvoa voidaan muuttaa suoraan lippurekisterissä käyttämällä erityisohjeet(esim. CLD suuntalipun tyhjentämiseksi), mutta ei ole ohjeita, jotka sallisivat lippurekisteriin pääsyn ikään kuin se olisi tavallinen rekisteri. Voit kuitenkin säästää

lippurekisteri pinoon tai AH-rekisteriin ja palauttaa lippurekisteri niistä ohjeiden LAHF, SAHF, PUSHF, PUSHFD, POPF ja POPFD avulla.

1.3.1. Tilan liput

Tilaliput (bitit 0, 2, 4, 6, 7 ja 11) kuvastavat aritmeettisten käskyjen, kuten ADD, SUB, MUL, DIV, tulosta.

Kantolippu CF asetetaan kannettäessä seniorilta merkittävä bitti/laina merkitsevimpään bittiin ja osoittaa ylivuodon etumerkittömässä kokonaislukuaritmetiikassa. Käytetään myös pitkässä aritmetiikassa.

Pariteettilippu PF asetetaan, jos tuloksen vähiten merkitsevä tavu sisältää parillisen määrän yhden bittejä. Alun perin tämä lippu oli tarkoitettu käytettäväksi viestintäohjelmat: Siirrettäessä dataa tietoliikennelinjoja pitkin, ohjausta varten voitiin lähettää myös pariteettibitti ja ohjeet pariteettilipun tarkistamiseksi helpottivat tiedon eheyden tarkistamista.

Ylimääräinen kantolippu AF asetetaan kuljetettaessa bitistä 3 tulos/laina sisään 3 tulos bitti. Tämä lippu on tarkoitettu käytettäväksi BCD (binäärikoodattu desimaali, BCD) aritmetiikka.

ZF nolla -lippu asetetaan, jos tulos on nolla.

Etumerkkilippu SF on yhtä suuri kuin tuloksen merkitsevimmän bitin arvo, joka on etumerkillisessä aritmetiikassa etumerkkibitti.

Ylivuoto lippu OF asetetaan, jos kokonaislukutulos on liian pitkä mahtumaan kohdeoperandiin (rekisteriin tai muistipaikkaan). Tämä lippu ilmaisee ylivuodon etumerkittyssä kokonaislukuaritmetiikassa.

Näistä lipuista vain CF-lippu voidaan muuttaa suoraan STC-, CLC- ja CMC-ohjeiden avulla.

Tilaliput mahdollistavat saman aritmeettisen käskyn antamisen tulos kolmesta erilaisia ​​tyyppejä: Etumerkitön, etumerkillinen ja binäärikoodattu desimaali (BCD) kokonaisluku. Jos tulosta pidetään etumerkittömänä numerona, CF-lippu näyttää ylivuotoehdon (carry tai Borrow), etumerkitylle tulokselle siirto tai laina näyttää OF-lipun ja BCD-tuloksen kanna/laina näyttää AF:n. lippu. SF-lippu heijastaa etumerkillisen tuloksen etumerkkiä, ZF-lippu heijastaa sekä etumerkitöntä että etumerkillistä nollatulosta.

Pitkän kokonaisluvun aritmetiikassa CF-lippua käytetään yhdessä ADC- ja vähennys- ja lainauskäskyjen (SBB) kanssa siirtämään siirto- tai lainaus pitkän luvun lasketusta numerosta toiseen.

Ohjeet

ehdollinen

siirtyminen Jcc (siirtymä

ehto cc ), SETcc (set

merkitys

tulostavu

riippuvuuksia

ehdot cc ),LOOPcc (organisaatio

ja CMOVcc (ehdollinen

kopiointi)

käyttää

yksi tai useampi

tilaliput tilan tarkistamiseksi. Esimerkiksi JLE-hyppykäsky (hyppää, jos pienempi tai yhtä suuri) tarkistaa ehdon "ZF = 1 tai SF ≠ OF".

PF-lippu otettiin käyttöön yhteensopivuuden vuoksi muiden mikroprosessoriarkkitehtuurien kanssa, ja sitä käytetään harvoin aiottuun tarkoitukseen. Sen yleisempi käyttö on yhdessä muiden tilalippujen kanssa liukulukuaritmetiikassa: vertailukäskyt (FCOM, FCOMP jne.) matemaattisessa rinnakkaisprosessorijoukossa olevat ehtoliput C0, C1, C2 ja C3 ovat siinä, ja näitä lippuja voidaan kopioida. lippurekisteriin. Tätä varten on suositeltavaa käyttää FSTSW AX -käskyä tallentamaan apuprosessorin tilasana AX-rekisteriin ja SAHF-käskyä kopioimaan AH-rekisterin sisältö lippurekisterin alhaisiin 8 bittiin, jolloin C0 päättyy. CF-lipussa, C2 PF-lipussa ja C3 ZF-lipussa. C2-lippu asetetaan esimerkiksi FUCOM-vertailukäskyyn, jos argumentit eivät ole vertailukelpoisia (NaN tai ei-tuettu muoto).

1.3.2. Ohjauslippu

Suunta lippu DF (lippurekisterin bitti 10) ohjaa merkkijonokäskyjä (MOVS, CMPS, SCAS, LODS ja STOS) - lipun asettaminen vähentää osoitteita (käsittelyrivit korkeista alhaisiin osoitteisiin), nollaus lisää osoitteita. STD- ja CLD-ohjeet asettavat ja poistavat DF-lipun.

1.3.3. Järjestelmäliput ja IOPL-kenttä

Järjestelmäliput ja IOPL-kenttä ohjaavat käyttöympäristöä, eikä niitä ole tarkoitettu sovellusohjelmien käyttöön.

Keskeytyksen aktivointimerkki JOS — tämän lipun tyhjentäminen estää vastaamisen peitettyihin keskeytyspyyntöihin.

Jäljityslippu TF – tämän lipun asettaminen sallii askel askeleelta -tilassa virheenkorjaus, kun jokaisen valmistumisen jälkeen

Ohjeet, ohjelma keskeytyy ja kutsutaan erityinen keskeytyskäsittelijä.

IOPL-kenttä näyttää I/O-prioriteettitason suoritettava ohjelma tai tehtävät: jotta ohjelma tai tehtävä voi suorittaa I/O-käskyjä tai muuttaa IF-lippua, sen nykyinen taso prioriteetin (CPL) on oltava ≤ IOPL.

Tehtävän sisäkkäinen lippu NT – tämä lippu asetetaan, kun nykyinen tehtävä on "sisättynä" toiseen, keskeytettyyn tehtävään ja nykyisen tehtävän TSS-tilasegmentti tarjoaa palautetta edellisen tehtävän TSS:n kanssa. IRET-käsky tarkistaa NT-lipun sen määrittämiseksi, onko paluu tehtävien välinen vai sisäinen.

Jatka lippu RF:tä käytetään virheenkorjausvirheiden peittämiseen.

VM - Tämän lipun asettaminen suojatussa tilassa aiheuttaa siirtymisen virtuaaliseen 8086-tilaan.

Kohdistustarkistuslippu AC – tämän lipun asettaminen yhdessä AM-bitin kanssa CR0-rekisterissä mahdollistaa operandin kohdistuksen ohjauksen käytettäessä muistia: kohdistamattoman operandin käyttö aiheuttaa poikkeuksen.

VIF – virtuaalinen kopio IF-lipusta; käytetään yhdessä VIP-lipun kanssa.

VIP – asetettu osoittamaan odottavan keskeytyksen olemassaolo.

ID - Mahdollisuus muuttaa tätä lippua ohjelmallisesti lippurekisterissä osoittaa CPUID-käskyn tuen.

1.4. Segmenttirekisterit

Prosessorissa on 6 ns. segmenttirekisteriä: CS, DS, SS, ES, FS ja GS. Niiden olemassaolo johtuu RAM-muistin organisoinnin ja käytön erityispiirteistä.

16-bittiset rekisterit pystyivät käsittelemään vain 64 kilotavua RAM-muistia, mikä ei selvästikään riitä enemmän tai vähemmän kunnolliseen ohjelmaan. Siksi ohjelmalle varattiin muistia useiden segmenttien muodossa, jotka olivat kooltaan 64 kt. Samaan aikaan absoluuttiset osoitteet olivat 20-bittisiä, mikä mahdollisti jo 1 Mt RAM-muistin osoittamisen. Herää kysymys: kuinka voit tallentaa 20-bittisiä osoitteita 16-bittisillä rekistereillä? Tämän ongelman ratkaisemiseksi osoite jaettiin offsetiksi. Kanta on segmentin alun osoite ja offset on segmentin tavunumero. Segmentin alun osoitteelle asetettiin rajoitus - sen piti olla 16:n kerrannainen. Tässä tapauksessa viimeiset 4 bittiä olivat yhtä suuria kuin 0, eikä niitä tallennettu, vaan ne olivat implisiittisiä. Näin saatiin kaksi 16-bittistä osoitteen osaa. Saadakseen

neljä absoluuttista osoitetta lisättiin tietokantaan nolla bittiä, ja tuloksena oleva arvo lisättiin offsetilla.

Segmenttirekistereihin tallennettiin koodisegmentin (CS - koodisegmentti), datasegmentin (DS - datasegmentti) ja pinosegmentin (SS - pinosegmentti) alun osoite. ES-, FS- ja GS-rekisterit lisättiin myöhemmin. Muistimalleja oli useita, joista jokainen sisälsi yhden tai useamman koodisegmentin ja yhden tai useamman datasegmentin allokoinnin ohjelmalle: pieni, pieni, keskikokoinen, kompakti, suuri ja valtava. Assembly-ohjeissa oli tiettyjä konventioita: hyppyosoitteet segmentoitiin CS-rekisterin mukaan, datahakuja DS-rekisteri ja pinokäytöt SS-rekisterin mukaan. Jos ohjelmalle oli varattu useita segmenttejä koodia tai dataa varten, CS- ja DS-rekisterien arvoja oli muutettava päästäkseen toiseen segmenttiin. Oli niin sanottuja "lähellä" ja "kaukana" siirtymiä. Jos komento, johon piti hypätä, oli samassa segmentissä, niin siihen hyppäämiseen riitti vain IP-rekisterin arvon muuttaminen. Tällaista siirtymää kutsuttiin lähellä. Jos komento, johon siirtyminen on tehtävä, oli eri segmentissä, niin siirtymistä varten oli tarpeen muuttaa sekä CS-rekisterin arvoa että IP-rekisterin arvoa. Tällaista siirtymää kutsuttiin pitkän matkan ja se kesti kauemmin.

32-bittisten rekisterien avulla voit osoittaa 4 Gt muistia, mikä riittää jo mille tahansa ohjelmalle. Windows suorittaa jokaisen Win32-ohjelman erillisessä virtuaalitilassa. Tämä tarkoittaa, että jokaisella Win32-ohjelmalla on 4 Gt osoiteavaruutta, mutta se ei tarkoita, että jokaisella ohjelmalla on 4 Gt fyysinen muisti, mutta vain, että ohjelma voi käyttää mitä tahansa osoitetta näissä rajoissa. Ja Windows tekee kaiken tarvittavan varmistaakseen, että ohjelman käyttämä muisti "on olemassa". Tietenkin ohjelman on noudatettava vahvistettuja sääntöjä

Windows, muuten tapahtuu yleinen suojausvirhe.

Win32-arkkitehtuurissa osoitetta ei tarvinnut erottaa kanta- ja offset-osoitteisiin, eikä tarvetta muistimalleille. 32-vuotiaana

käytetään eri tavalla 1. Aikaisemmin ohjelman yksittäiset osat piti liittää yhteen tai toiseen segmenttirekisteriin ja tallentaa/palauttaa DS-rekisteri siirryttäessä toiseen datasegmenttiin tai segmentoida tiedot eksplisiittisesti toiseen rekisteriin. 32-bittisessä arkkitehtuurissa tämä ei ole enää välttämätöntä, ja yksinkertaisimmassa tapauksessa segmenttirekisterit voidaan unohtaa.

1.5. Pinon käyttäminen

Jokaisella ohjelmalla on muistialue, jota kutsutaan pinoksi. Pinoa käytetään parametrien välittämiseen proseduurille ja proseduurien paikallisten tietojen tallentamiseen. Kuten tiedät, pino on muistialue, jonka kanssa työskennellessä on noudatettava tiettyjä sääntöjä, nimittäin: ensin pinoon tulleet tiedot poistetaan sieltä viimeisenä. Toisaalta, jos ohjelmalle on varattu jonkin verran muistia, lukemiselle ja kirjoittamiselle ei ole fyysisiä rajoituksia. Miten nämä kaksi ristiriitaista periaatetta sovitetaan yhteen?

Oletetaan, että meillä on funktio f1, joka kutsuu funktiota f2, ja funktio f2 puolestaan ​​kutsuu funktiota f3. Kun f1-funktiota kutsutaan, sille varataan pinossa tietty tila paikallistiedoille. Tämä tila varataan vähentämällä ESP-rekisteristä tarvittavan muistin kokoa vastaava arvo. Minimikoko varattu muisti on 4 tavua, ts. vaikka proseduuri vaatisi 1 tavun, sen tulisi kestää 4 tavua.

F1-toiminto suorittaa joitakin toimintoja ja sitten kutsuu

funktio f2 kutsuu funktiota f3, joka myös varaa tilaa pinossa. F3-funktio ei kutsu muita toimintoja, ja valmistuttuaan sen on vapautettava pinossa tilaa lisäämällä ESP-rekisteriin arvo, joka vähennettiin funktiota kutsuttaessa. Jos toiminto f3 ei palauta ESP-rekisterin arvoa, niin työtään jatkava toiminto f2 ei pääse käsiksi omiin tietoihinsa, koska Hän etsii

joka oli ennen hänen soittoaan.

Proseduuritasolla on siis noudatettava pinon kanssa työskentelyn sääntöjä - viimeksi pinossa tilaa vieneen toimenpiteen on vapautettava se ensin. Jos tätä sääntöä ei noudateta, ohjelma ei toimi oikein. Mutta jokainen toimenpide voi päästä pinoalueelleen millä tahansa tavalla. Jos joutuisimme noudattamaan pinon kanssa työskentelyn sääntöjä kussakin toimenpiteessä, meidän olisi siirrettävä tietoja pinosta toiselle muistialueelle, mikä olisi erittäin hankalaa ja hidastaisi suoritusta huomattavasti. ohjelmasta.

Jokaisella ohjelmalla on tietoalue, jossa globaalit muuttujat sijaitsevat. Miksi pinoon tallennetaan paikallista dataa? Tämä tehdään ohjelman käyttämän muistin määrän vähentämiseksi. Jos ohjelma on peräkkäin kutsua useita proseduureja, niin kullakin hetkellä on varattu tilaa vain yhden proseduurin tiedoille, koska Pino on varattu ja vapautettu. Tietoalue on olemassa niin kauan kuin ohjelma on käynnissä. Jos paikallista dataa sijaitsisi data-alueella, paikallinen tietotila olisi varattava kaikille ohjelmatoimenpiteille.

Paikallisia tietoja ei alustata automaattisesti. Jos yllä olevassa esimerkissä funktio f2 funktion f3 jälkeen kutsuu funktiota f4, niin funktio f4 ottaa pinossa sen paikan, jossa funktio f3 oli aiemmin, jolloin funktio f4 "perii" funktion f3 tiedot. Siksi jokaisen toimenpiteen on huolehdittava paikallisten tietojensa alustamisesta.

2. Assembly-kielen peruskäsitteet

2.1. Tunnisteet

Assembly-kielessä tunnisteen käsite ei eroa muiden kielten tunnisteen käsitteestä. Voit käyttää latinalaisia ​​kirjaimia, numeroita ja _-merkkejä. ? @ $ , ja piste voi olla vain tunnuksen ensimmäinen merkki. Isoja ja pieniä kirjaimia pidetään vastaavina.

2.2. Kokonaislukuja

SISÄÄN Assembly-ohjelmassa kokonaisluvut voidaan kirjoittaa binääri-, oktaali-, desimaali- ja heksadesimaalijärjestelmät Laskeminen Numerojärjestelmän määrittäminen numeron lopussa