Sýndarvélar og stýriflæði
Sum bakhönnunarverkefni snúast ekki aðeins um eina umbreytingu eða einn samanburð. Þau geta skilgreint eigið skipanasett eða breytt stýriflæði forritsins svo erfitt verði að sjá hvaða kóði keyrir næst.
Þessi kafli byggir á köflunum um smalamál, kyrrstæða greiningu og kvika greiningu.
Sérsniðnar sýndarvélar
Í slíkum verkefnum er sýndarvél (e. virtual machine, VM) lítið forrit sem túlkar sérsniðinn bætakóða. Þetta er ekki sýndarvél til öryggiseinangrunar heldur hluti af forritinu sem við erum að greina.
Sýndarvélin hefur oft:
- bætakóða sem geymir sýndarskipanirnar;
- sýndargista, stafla eða minnissvæði;
- skipunarbendi sýndarvélarinnar sem segir hvaða skipun kemur næst;
- túlk sem sækir, afkóðar og framkvæmir hverja skipun.
flowchart TB
Bytecode["Bætakóði<br/>sýndarskipanir forritsins"] --> Fetch["Sækja aðgerðarkóða og viðföng<br/>á stað IP"]
Fetch --> Decode["Afkóða skipun"]
Decode --> Execute["Framkvæma skipun"]
Execute -.->|les eða breytir| State["Ástand sýndarvélarinnar<br/>gistar · stafli · minni"]
Execute --> UpdateIP["Uppfæra IP<br/>færa áfram eða stökkva"]
style State fill:#164e63,stroke:#22d3ee,color:#ffffff
Skipunarbendirinn ip velur stað í bætakóðanum. Túlkurinn sækir skipunina þar, afkóðar hana og framkvæmir með því að lesa eða breyta ástandi sýndarvélarinnar. Að lokum færist ip áfram eða fær nýtt gildi ef skipunin veldur stökki, og lykkjan hefst aftur.
Túlkunarlykkjan getur litið svona út í einfölduðu C-líku úttaki:
while (running) {
opcode = bytecode[ip++];
switch (opcode) {
case OP_LOAD: /* ... */ break;
case OP_ADD: /* ... */ break;
case OP_JUMP: /* ... */ break;
case OP_HALT: running = 0; break;
}
}
Breytan opcode geymir aðgerðarkóða (e. opcode) sem segir hvaða sýndarskipun á að framkvæma. Bætin á eftir honum geta verið viðföng, til dæmis númer gista, fast gildi eða áfangastaður stökks.
Vinnulag
- Við finnum túlkunarlykkjuna og bætakóðann sem hún vinnur úr.
- Við skráum lengd, viðföng og áhrif hvers aðgerðarkóða í töflu.
- Við rekjum sýndarskipanirnar og fylgjum breytingum á gistum, stafla og minni.
- Ef skipanirnar eru margar getum við skrifað lítinn túlk sem líkir eftir sýndarvélinni.
| Aðgerðarkóði | Viðföng | Áhrif |
|---|---|---|
0x01 |
gisti, gildi | setur gildi í gisti |
0x02 |
tveir gistar | leggur gildi saman |
0x03 |
áfangastaður | breytir skipunarbendinum |
Taflan er aðeins dæmi. Sérsniðin sýndarvél getur notað allt aðra kóða, lengdir og hegðun.
Flókið stýriflæði
Stýriflæði (e. control flow) lýsir því í hvaða röð skipanir og grunnblokkir forrits keyra. Þýðandi eða torlæsingartól getur breytt skýrum greinum og lykkjum í flóknara form án þess að breyta niðurstöðunni.
Ein algeng aðferð notar stýribreytu og miðlæga stýringarlykkju (e. dispatcher loop). Hver grein framkvæmir lítið verk, velur næsta gildi stýribreytunnar og fer aftur í lykkjuna. Í bakþýðanda sjáum við þá oft stórt switch, margar úthlutanir á sömu breytu og stökk aftur á sama stað.
Við vinnum okkur út úr þessu með því að:
- finna breytuna sem stjórnar næstu grein;
- skrá hvaða grein getur leitt í hvaða aðra grein;
- teikna stýriflæðirit (e. control-flow graph, CFG);
- sameina litlu skrefin og endurgera læsilegri mynd af virkni forritsins.
Kvik greining getur staðfest eina raunverulega leið en kyrrstæð greining hjálpar okkur að finna leiðir sem tiltekið inntak keyrir ekki.
Æfingar
Framhaldsverkefni um sérsniðnar sýndarvélar og flókið stýriflæði:
- Golem: Við greinum forrit sem byggir á eigin sýndarvél.
- Spaghetti: Við greinum forrit þar sem stýriflæðið hefur verið gert vísvitandi flókið.