Kako programi postanejo izvršljivi

 

V tem poglavju naj bi spoznali pomen zbiranja ali prevajanja, povezovanja in nalaganja programov. To so faze, ki jih mora prehoditi praktično vsak program pri prehodu od njegove izvorne kode v tekstovni obliki do izvedbe v računalniku. Nekoliko drugače potekajo stvari  predvsem  pri programih, ki smo jih zapisali v primernem skriptnem jeziku.  Pa tudi pri programih, pisanih v jeziku Java najdemo nekaj podobnosti, pa tudi nekaj razlik s to - klasično pripravo programa.

Grobo poteka predelava programa od izvorne kode v njegovo izvedljivo obliko po naslednjih korakih:

 

Programer napiše program s primernim urejevalnikom besedila in pomni datoteko. Recimo, da je njegovemu programu ime MojProgram. Tipično imajo programi, pisani v jeziku C, podaljšek ».c«, programi v pascalu ali Delfiju podaljšek  ».pas«, programi v basicu podaljšek ».bas«, programi v Javi podaljšek ».java«. Torej datoteko s programom pomnimo z ustreznim popolnim imenom, kot na primer »Mojprogram.c«, »MojProgram.pas«, »MojProgram.bas«, »MojProgram.java«.

Ne nazadnje bi lahko program napisali v zbirnem jeziku (ta jezik je bolj preprost, so pa taki programi običajno težje rezumljivi in tudi samo programiraje je težje). Verjetno bi program v zbirnem jeziku imel podaljšek kot ».asm«, torej na primer »MojProgram.asm«.   

Sledi prevod programa s primernim prevajalnikom. Tako dobimo program, preslikan v takoimenovano objektno kodo. Zelo pogosto (ne pa nujno) imajo tako  datoteke s tako prevedenimi programi enako ime, pa drugačen podaljšek. V primeru programov v jeziku c  bi tako dobili »MojProgram.o«, včasih tudi »MojProgram.obj«. V primeru pascalskega ali programa v delphiju bi datoteka s prevedenim programom imela ime »MojProgram.tpu«. V primeru javanskega programa dobimo eno ali več datotek s podaljškom ».class« (torej v našem primeru »Mojprogram.class«).

Včasih imajo datoteke s prevedenimi programi oznako .obj (na primer MojProgram.obj), kar nakazuje, da je to program, zakodiran v objektni kodi (raje recimo ciljni kodi, saj to nima nobene zveze z objektno usmerjenim programiranjem)

Če pričakujemo, da se bo tako prevedeni program že izvedel in prikazal rezultate, bomo razočarani. Tudi iz gornje slike je razvidno, da mora računalnik še prej opraviti povezovanje in nato program tudi naložiti.

 

Povezovanje programa

 

Prevedeni program je tipično že preslikan v dvojiško kodo, razumljivo računalniku. (Izjema je tu java, kjer pri prevodu programa dobimo takoimenovano »byte-code«, ki je »strojna koda« navideznega računalnika, kateremu pravimo »Javanski navidezni stroj » (JVM, Java Virtual Machine).

Vendar prevedena oblika programa največkrat še ni »izvršljiva«.  Pomislimo na primer na program, ki bi moral izvesti zapletene matematične operacije, nato pa rezultat izpisati na zaslon ali pa celo shraniti v primerno datoteko na disku.  Pravkar prevedeni program sicer zna izvajati najbolj preproste celoštevilčne operacije, ne pa zapletenih matematičnih računanj. In čisto nič ne ve, kako naj nekaj, morda celo lepo oblikovano zapiše na zaslon. Kaj šele, da bi znal kaj zapisati v primerno datoteko.

Take operacije, ki so sicer zelo pogoste, je moral nekdo za nas vnaprej sprogramirati, mi pa moramo našemu programu dodati tiste, ki jih pač potrebuje.

Stvar spominja na to, da tudi v vsakdanjem življenju ne vemo vsega na pamet. Če kaj potrebujemo, moramo imeti na voljo knjižnico z enciklopedijami, slovarji, priročniki ipd.

Tudi pri našem programu je podobno. Na voljo moramo imeti knjižnjice uporabnih programskih modulov oziroma podprogramov. Našemu programu moramo dodati tiste, ki jih potrebuje.

Vendar tudi tega dodajanja ne naredimo sami. Podobno, kot je za prevod poskrbel poseben program – prevajalnik, poskrbi za navezavo teh potrebnih podprogramov program – povezovalnik  (angleško linker)

Povezovalnik naredi naslednje:

·         Ugotovi, katere programske module (oziroma datoteke) želimo priključiti našemu programu

·         Odloči, na katerih računalniških naslovih naj bi ležal naš program in priključeni moduli.

·         Poišče še nepojasnjene simbole in jih poveže z naslovi v priključenih modulih

·         Sestavi novo, enotno  binarno datoteko, v kateri ni nerazjasnjenih zunanjih simbolov. Včasih imajo take datoteke oznako ».exe«, kar naj bi povedalo, da so to že izvršljivi programi.

Spodnja slika ponazoruje delo, ki ga opravi povezovalnik:

 

 

Kako je zakodiran izvršljivi program?

 

To za vsakdanjega uporabnika računalniških programov niti ni pomembno, zaradi popolnosti pa le povejmo:

To, kar dobimo iz povezovalnika, je lahko zakodirano v absolutni ali pa premakljivi kodi (absolute code, relocatable code).

Absolutna koda terja, da program namestimo na točno določene lokacije v pomnilniku. To pa je smiselno le pri zelo namenskih programih, na primer v mikroračunalnikih za avtomatizacijo različnih naprav. V splošno namenskih računalnikih, med katere sodijo tudi popularni PC-ji, pa to ni primerno, saj pomnimo in izvajamo običajno po več programov in ne moremo vnaprej napovedati, kje v pomnilniku računalnika bo ležal kateri program.

Kar pomislimo na primer, da imamo program, ki naj bi bil nameščen v pomnilnik med 3000. in 5000. pomnilno lokacijo. In recimo, da moramo v takem programi imeti (pogojni) programski skok na lokacijo 3400. V programu bi imeli torej ukaz, podoben naslednjemu:

GO TO 3400     (ali bolje v zbirnem jeziku JUMP 3400)

Tak program pravilno deluje, če ga naložimo na predvideno mesto v pomnilniku. Kaj pa, če tam ni prostora in ga moramo zapisati kam drugam? Seveda bo zanesljivo nekaj narobe. Kdo ve, kaj se takrat nahaja na naslovu 3400.

Premakljiva (relocatable) koda to rešuje tako, da so vsi naslovi relativni in ne absolutni.  Programski skok bi morali zapisati tako:

GO TO »15 ukazov naprej«  ( ali v zbirnem jeziku verjetko kaj takega: SKIP 15)

Tak program bo deloval pravilno, če ga namestimo od 3000 lokacije naprej, ali od 4000 dalje. Pravzaprav je vseeno, kam ga namestimo v pomnilniku.

Seveda smo z zgornjim primerom le pojasnili problem. Absolutna ali premakljiva koda sta v resnici različici kodiranja na strojnem nivoju.

 

Proces nalaganja

 

Nalaganje  (loading)  je proces kopiranja izvršljive kode v pomnilnik računalnika, torej na dejanske fizične lokacije. Tipično kopira tak program z zunanje pomnilne enote, najbolj pogosto z diska. Postopek nalaganja ponazoruje spodnja slika:

Nalagalnik naredi naslednje:

·         Ugotovi (na primer iz formata zapisa), ali gre za absolutno ali premakljivo kodo.

·         V primeru absolutne kode prepiše le-to na zahtevane pomnilniške lokacije

·         V primeru premakljive kode ugotovi, kje ima prostor v pomnilniku in prepiše kodo ta tako ugotovljeno mesto

·         Vzpostavi takoimenovano »sliko prpograma«, torej začetne vrednosti delovnih registrov računalnika)

·         In tako spo pripravljeni na izvajanje programa J

 

Še nekaj zanimivih vprašanj

 

Že že, razumem vlogo nalagalnika. Vendar je tudi nalagalnik program. Kdo pa naloži nalagalnik?

Že že, razumem vlogo prevajalnika in povezovalnika. Vendar sta tudi to samo programa. Kdo pa je njih prevedel in povezal.?

In v kakšnem jeziku je bil napisan prevajalnik, če prej prevajalnika še ni bilo?

 

Za konec še o dinamičnem povezovanju


Dinamično povezovanje (dynamic linking) prestavlja proces povezovanja na čim kasnejši čas, celo na čas izvajanja programa (run time). Namesto povezav na prave module ima naš program nekakšne štrclje (stub), tako da je sama dejanska funkcija oziroma podprogram izbran šele v času izvajanja. Zamisel je kar podobna večnamenskim orodjem,  ki jim dodelimo dejansko funkcijo šele ob trenutku uporabe.

Prednosti dinamičnega povezovanja najdemo v tem, da lahko take uporabne programske module uporablja več programov, ne da bi imel vsak svojo kopijo. Torej potrebujemo manj pomnilnika. Tudi popravki takih programskih orodij so takoj na voljo vsem programom in jih ni potrebno ponovno povezovati.