25.07.2013 Views

3. Razvojno okruženje

3. Razvojno okruženje

3. Razvojno okruženje

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>3.</strong> <strong>Razvojno</strong> <strong>okruženje</strong><br />

Razvojna sredstva savremenih računara opšte namene kakve su PC mašine (desktops) koriste<br />

veoma složene tehnike za prevođenje programa kreiranih na nekim od HLL-ova. Pri tome u najvećem<br />

broju slučajeva izvorni kôd se direktno prevodi u binarni image-oblik koji se zatim load-uje u mašinu radi<br />

izvršenja. U suštini, ova sofisticirana razvojna sredstva prevode izvorni kôd u relokatibilne module,<br />

ponekad koristeći, a često i nekoristeći debug i simboličke informacije koje mogu biti od koristi<br />

projektantima. Pri tome, složeni i dobro optimizirani linker-i i loader-i dinamički kombinuju ove module,<br />

i u trenutku izvršenja aplikacije preslikavaju ove module u specifične memorijske lokacije.<br />

Sa druge strane, projektanti embedded sistema ne mogu da koriste ovakve beneficije iz nekoliko<br />

razloga. Kao prvo, embedded sistem se skoro uvek bazira na jedinstvenom (specifičnom) hardveru,<br />

hardver koji u suštini ne postoji (ne egzistira kao takav) kada se razvijalo razvojno sredstvo. Kao drugo,<br />

uprkos prednosti kojom se karakteriše procesor ugrađen u razvojno sredstvo, ipak postoji neznatna razlika<br />

u mašinskim jezicima između izabranog procesora i procesora ugrađenog u razvojnom okruženju,<br />

nezavisno od toga što oba procesora pripadaju istoj familiji (procesori Intel 286, 186, 288, 188, i td.).<br />

Pored toga, deo napora koje učini projektant moraju biti usmereni ka tome da se naredi razvojnom<br />

sredstvu na koji način da prevede izvorni kôd za specifični hardver embedded sistema. To znači da<br />

projektanti embeded sistema moraju da znaju mnogo više detalja o tome: a) na koji način njihova<br />

razvojna sredstva rade; b) kako izgleda razvojno <strong>okruženje</strong>; c) na koji način se izvršavaju programi.<br />

<strong>3.</strong>1 Radno <strong>okruženje</strong><br />

Pored dobrog poznavanja ISA (Instruction Set Architecture) tj. procesora, da bi se kreirao efikasan<br />

embedded kôd, projektantu je dodatno potrebno da dobro poznaje i sledeće detalje:<br />

1) na koji način sistem koristi memoriju, uključujući i detalje koji se odnose na to na koji način<br />

procesor manipuliše magacinom,<br />

2) šta se dešava pri startup sistema, i<br />

3) na koji način se manipuliše sa prekidima i izuzecima?<br />

Da bi ukazali, sa nešto više detalja, na ove probleme analilziraćemo rad jednog tipičnog embedded<br />

sistema zasnovanog na procesorima iz familije Motorola 68000 (68K).<br />

<strong>3.</strong>2. Organizacija memorije<br />

Prvu stvar sa kojom se projektant embedded sistema suočava, a tiče se rada sistema, predstavlja<br />

način na koji on vidi memoriju, i kako se koristi ta memorija. Ilustracije radi, na slici <strong>3.</strong>1 prikazan je<br />

memorijski model procesora Motorola 68K kao jednog tipičnog reprezenta procesora koji se ugrađuju u<br />

embedded sisteme. Kao što se vidi sa slike <strong>3.</strong>1 sve što je na levoj strani u odnosu na U/I prostor može se<br />

implementirati kao ROM, a sve što je na desnoj kao RAM.<br />

Slika <strong>3.</strong>1. Memorijska mapa procesorskog sistema


<strong>3.</strong>2.1 Prostor namenjen sistemu<br />

Procesori iz familije Motorola 68K (kao i veći broj drugih 32-bitnih procesora) rezervišu prvih<br />

1024 memorijskih lokacija (256 reči) za potrebe vektorske tabele. Vektori (exception vectors)<br />

predstavljaju hard-wired adrese koje procesor koristi radi identifikacije kôda (programa) koga treba<br />

izvršiti, u trenutku kada procesor treba da manipuliše sa prekidima ili drugim izuzecima (tipični takvi<br />

izuzeci su deljenje sa nulom, ili greška zbog premašaja). Svaki vektor je dužine 4 bajta, a sistem podržava<br />

rad do 256 različitih vektora za obradu izuzetaka.<br />

<strong>3.</strong>2.2 Prostor namenjen programu<br />

Iznad sistemskog prostora nalazi se prostor u kome se čuvaju (memorisane su) instrukcije.<br />

Praktični razlog za ovakav izbor je sledeći: Sistemski i kôdni prostor je poželjno da budu kontinualni i<br />

smešteni u jednom istiom ROM memorijskom čipu.<br />

<strong>3.</strong>2.3 Prostor namenjen podacima<br />

Iznad kôdnog prostora egzistira ROM prostor za podatke. U ovom prostoru se čuvaju konstante<br />

kakve su poruke o greškama koje se javljaju u toku rada koje obično treba saopštiti na displeju, ili drugi<br />

literali.<br />

Iznad prostora za podatke, organizacija memorije nije više tako regularna i mnogo je zavisnija od<br />

hardverskih ograničenja dizajna. To znači da memorijski model prikazan na slici <strong>3.</strong>1 predstavlja samo<br />

jedan ilustrativni primer kako se memorija može organizovati, ali ne mora da znači da je to i pravilo. No,<br />

nezavisno od svega, sledeća tri glavna Read/Write RAM memorijska prostora moraju egzistirati kod<br />

svakog sistema: a) magacin (stack); b) slobodan memorijski prostor (free memory); i c) heap.<br />

• Magacin - Magacin se koristi za čuvanje traga o tekućem i svim suspendovanim kontekstima<br />

izvršenja programa. To znači da se u magacinu privremeno pamte: a) vrednosti o svim tekuće<br />

aktuelnim (live) promenljivama; i b) vrednosti adresa povratka (return addresses) za sve funkcije i<br />

prekide. Vrh magacina uobičajeno se postavlja na gornji kraj memorije, a magacin stalno raste<br />

prema nižim adresama.<br />

• Slobodan memorijski prostor - Svim statički alociranim Read/Write promenljivama se dodeljuju<br />

lokacije u slobodnom memorijskom prostoru (free memory). Globalne promenljive predstavljaju<br />

najčešći oblik statičko alociranih promenljivih, ali se i C "static" takođe čuvaju u ovom prostoru.<br />

Bilo koja promenljiva koja se može modifikovati, a tipa je globalna promenljiva smešta se u free<br />

memoriji.<br />

• Heap - Svi dinamičko alocirani (kreirani pomoću new ili malloc()) objekti i promenljive se<br />

čuvaju u heap-u. Obično, memorija koja preostane nakon dodele magacina kao i free memorija<br />

pridružuje se heap-u. Heap standardno povezuje strukture podataka kojima upravljaju rutine iz<br />

compiler run-time package-a. Najveći broj embedded sistema ne koristi heap.<br />

<strong>3.</strong>2.4 Nezauzeti memorijski prostor<br />

Prekid na sredini slike <strong>3.</strong>1 odnosi se na slobodan (nezauzet) adresni prostor koji nije pridružen<br />

bilo kojoj memoriji. Recimo, jedan tipičan embedded sistem može da ima instalirano po nekoliko<br />

megabajtova ROM prostora za instrukcije i podatke i još po nekoliko megabajtova RAM prostora. S<br />

obzirom da Motorola 68K, kao i veći broj 32-bitnih procesora, može da adresira memorijski prostor<br />

obima 16 MB pa i veći, pa zbog toga veliki deo ovog prostora obično ostaje neiskorišćen.


<strong>3.</strong>2.5 Ulazno/izlazni prostor<br />

Zadnja memorijska komponenta se odnosi na memorijsko-preslikavanje perifernih uređaja. Na<br />

slici <strong>3.</strong>1 ovi uređaji se nalaze (locirani su) u U/I prostoru. Nasuprot nekim procesorima (kakvi su oni iz<br />

Intelove familije x86) procesori iz familije Motorola 68K ne podržavaju rad izdvojenog U/I prostora,<br />

nego memorijsko preslikanog U/I-a. Obično, radi lakšeg dekodiranja, adrese U/I uređaja su razmeštene<br />

(scattered) po memoriji na raznim lokacijama.<br />

<strong>3.</strong>3 Startup sistema<br />

Dobro razumevanje layout-a memorije predstavlja projektantu solidnu osnovu da korektno razume<br />

startup sekvencu. Radi lakše dalje analize usvojićemo da je program embedded uređaja već load-ovan u<br />

korektan memorijski prostor (najčešće se to radi programiranjem EPROM-a i postavljanjem tog<br />

memorijskog čipa u korektno mesto na sistemskoj ploči).<br />

Startup sekvencu čine sledeće dve faze:<br />

• hardverska faza - aktiviranjem linije RESET procesor izvršava hardversku fazu. Namena ovog<br />

dela startup-a je da usmeri CPU da počne sa izvršenjem programa ili nekog drugog kôda koji će<br />

preneti upravljanje programu.<br />

• softverska faza - odgovorna je za inicijalizaciju hardverskih elemenata kao i ključnih struktura<br />

podataka u memoriji.<br />

Na primer, kada mikroprocesor Motorola 68K izađe iz stanja RESET on obavlja sledeće dve<br />

aktivnosti:<br />

1. Pribavlja četvorobajtnu adresu koja se čuva na lokaciji 0x000000 i kopira ovu adresu u SP<br />

registar, čime se određuje početak magacina. Uobičajeno je da se SP registar inicijalizira<br />

na vrh RAM prostora tj. 0xFFFFFE, iz razloga što magacin raste naniže. Nakon toga CPU<br />

adresira četiri bajta smeštenih u memorijskim lokacijama 000004-000007 i smešta ovu 32bitnu<br />

vrednost u programski brojač. Konačno, procesor pribavlja instrukciju na koju<br />

ukazuje stanje programskog brojača i počinje sa izvršenjem programa. Ove aktivnosti<br />

pripadaju hardverskoj fazi.<br />

2. Početak izvršenja programa karakteriše softversku fazu. U ovom trenutku CPU je pod<br />

kontrolom softvera ali još nije spreman za izvršenje aplikacije. Umesto toga on izvršava<br />

deo kôda kojim se inicijaliziraju različiti hardverski resursi (tajmeri, kontroleri prekida,<br />

DMA kontroleri i td.) kao i strukture podataka koje se čuvaju u memoriji a koje su<br />

neophodne radi kreiranja kompletnog radnog (run-time) okruženja.<br />

<strong>3.</strong><strong>3.</strong>1 Ciklus odziv-na-prekid<br />

Koncepsijski posmatrano prekidi su relativno jednostavni za procesiranje. Nakon prijema INTR<br />

signala CPU "ostavlja na stranu" ono što tekuće radi, izvršava instrukcije kojima se opslužuje prekid, a<br />

zatim se ponovo vraća na izvršenje prekinutog zadatka. Kod ovakvog načina procesiranja kritičan<br />

element je sledeći: Hardver CPU-a je taj koji vodi računa o prenosu upravljanja sa jednog zadatka na<br />

drugi, kao i ponovnog povratka. Pri tome, porjektant sistema ne može da kôdira (utiče na) ovaj prenos<br />

putem kreiranja nekog memorijskog niza instrukcija iz prostog razloga što ne postoji način kojim se može<br />

predvideti trenutak kada će se zahtev za prekid javiti. I pored toga što je ovaj mehanizam prenosa skoro<br />

identičan kod svih arhitektura, ipak neke male razlike postoje. One se odnose na to kako različiti CPU-ovi<br />

vrše obradu zahteva za prekid.<br />

Ključne stavke koje se odnose na obradu prekida, a koje projektant treba da razume su:<br />

1. Kako CPU zna gde da pronađe kôd (tj. početnu adresu) prekidne rutine?<br />

2. Koje akcije CPU treba da preuzme kako bi zapamtio, a kasnije i obnovio "kontekst" glavnog<br />

thread-a?<br />

<strong>3.</strong> Kada treba dozvoliti rad prekidima?<br />

Kao što smo napomenuli, prvih 1024 bajtova memorije je rezervisano za čuvanje exception<br />

vektora. Na odgovarajućim lokacijama u vektor tabeli nalaze se početne instrukcije za obradu izuzetaka.


Kada periferija generiše zahtev za prekid, a CPU-u je dozvoljleno da prihvata taj zahtev, tada<br />

Motorola 68K (važi i za veći broj drugih mikroprocesora) obavlja sledeće aktivnosti:<br />

• smešta adresu naredne instrukcije prekinutog programa (povratnu adresu) u magacin,<br />

• puni početnu adresu (vektor) ISR-a (Interrupt Service Routine) iz vektorske tabele u programski<br />

brojač,<br />

• zabranjuje rad drugim prekidima,<br />

• nastavlja sa normalnim ciklusima tipa fetch-execute, ali u ovom trenutku pribavlja instrukcije koje<br />

pripadaju ISR-u, i<br />

• na kraju izvršenja ISR-a povratak iz prekidnog programa (ISR) u prekinuti vrši se naredbom RTE<br />

(return from exception).<br />

<strong>3.</strong><strong>3.</strong>2 Pozivi funkcije i okviri magacina<br />

Kada projektant kreira neku funkciju na HLL-u, kakav je recimo, C i asemblira je, kompajler je<br />

konvertuje u potprogram na asemblerskom jeziku. Ime potprograma na asemblerskom jeziku slično je<br />

imenu funkcije na C-u sa tom razlikom što ispred imena stoji simbol "_" (donja crta ili underscore). Na<br />

primer, main() postaje _main. Na sličan način kako se funkcija na C-u main() završava iskazom<br />

return, tako se i verzija na asemblerskom jeziku završava asemblersko jezičkim ekvivalentom: RTS.<br />

Na slici <strong>3.</strong>2 prikazana su dva potprograma FOO i BAR, jedan ugnežđen u okviru drugog. Glavni<br />

program poziva potprogram FOO koji zatim poziva potprogram BAR. Kompajler prevodi poziv BAR-a<br />

koristeći isti mehanizam kao i kod poziva FOO-a. Pri ovome je moguće obavljati automatsko smeštanje- i<br />

izbavljanje-iz magacina jer magacin se ponaša kao struktura tipa LIFO. Naime, operacijom PUSH adresa<br />

povratka se smešta u magacin, a operacijom POP se ona izbavlja iz magacina u trenutku povratka iz<br />

potprograma.<br />

Potprogram na asemblerskom jeziku poziva se naredbom JSR. Argument ove instrukcije je<br />

memorijska adresa koja ukazuje na početak potprograma. Kada procesor izvršava naredbu JSR on<br />

automatski smešta adresu naredne instrukcije pozivnog programa u magacin. Nakon toga počinje sa<br />

izvršenjem prve naredbe pozvanog programa. Na kraju pozvanog programa, obavljanjem instrukcije RTS,<br />

ponovo se vraćamo na izvršenje pozivnog programa sa one lokacije koju smo privremeno zapamtili u<br />

magacinu.<br />

Magacin se obično koristi za memorisanje lokalno promenljivih kao i argumenata funkcije. I<br />

pored toga što se smeštanje povratne adrese pozivnog programa kao i izbavljanje te adrese iz magacina<br />

obavlja po automatizmu od strane hardvera (ove aktivnosti se obavljaju u toku izvršenja naredbi JSR i<br />

RTS) kompajler je taj koji mora eksplicitno da generiše naredbe za ovakve aktivnosti na asemblerskom<br />

jeziku. Ove naredbe se koriste za manipulisanje memorijskim prostorom koji se dodeljuje lokalno<br />

promenljivim. U ovakvim situacijama različiti kompajleri koriste različite opcije. U opštem slučaju<br />

kompajler može da generiše kôd kojim se:<br />

• smeštaju u magacin svi argumenti<br />

• poziva funkcija<br />

• alocira memorija (u magacin) za sve lokalne promenljive<br />

• obavlja zadatak dodeljen funkciji<br />

• dealocira prostor dodeljen lokalno promenljivim<br />

• obavlja povratak od funkcije ka pozivnom programu<br />

• dealocira prostor koji se koristi za čuvanje argumenata.<br />

Skup celokupno dodeljenog prostora jednom pozivu funkcije (argumenti, povratne adrese, i<br />

lokalno promenljive) naziva se okvir magacina (stack frame). U okviru potprograma na asemblerskom<br />

jeziku okvir magacina nije ništa više od jednog lokalnog RAM bloka koji se adresira preko jednog<br />

internog registra CPU-a, nazvanog pokazivač okvira FP (frame pointer).


<strong>3.</strong>4 Run-time <strong>okruženje</strong><br />

Slika <strong>3.</strong>2 Potprogrami i šematski prikaz asemblersko-jezičkog potprograma<br />

Run-time <strong>okruženje</strong> čine sve softverske strukture (nisu eksplicitno kreirane od strane programera)<br />

koje podržavaju izvršenje programa. Struktura koja povezuje okvire-magacina se može smatrati kao deo<br />

run-time okruženja. Za programere na C-u druge dve glavne komponente koje čine run-time <strong>okruženje</strong> su<br />

startup kôd i run-time biblioteka.<br />

<strong>3.</strong>4.1 Startup kôd<br />

Startup kôd je softver koji premošćava vezu između hardverske startup faze i programa main().<br />

Softver za premošćavanje treba da se izvrši pri svakom RESET-u, i minimalno, treba da prenese<br />

upravljanje programu main(). Trivijalna implementacija startup-a može da predstavlja asemblerskojezički<br />

fajl koga čini samo sledeća instrukcija:<br />

JMP _main<br />

Da bi učinili ovaj kôd, koga čini samo jedna instrukcija, izvršivim, u toku startup-a, neophodno je<br />

da se pronađe način kako da se smesti adresa instrukcije JMP na memorijske lokacije 000004-000007.<br />

(Promeniti vrednost vektora izuzetka prve instrukcije u vektor tabeli koja se izvršava od strane<br />

procesora.)<br />

Standardna rešenja se ne baziraju na rešenju da se koristi direktni skok na main(). Kod realnih<br />

sistema, kada se izvršenje programa startuje po prvi put, prvo se standardno obavljaju i neke provere koje<br />

se odnose na integritet sistema, kakve su ROM checksum-test, RAM test, zatim se vrši relokacija kôda iz<br />

ROM u RAM prostor u cilju bržeg pristupa, nakon toga se obavlja inicijalizacija hardverskih resursa, a na<br />

kraju se postavlja ostalo potrebno <strong>okruženje</strong> za HLL C, pre nego što se konačno skoči na _main. Za<br />

razliku od desktop okruženja gde startup kôd ne treba nikada da se menja, kod embedded okruženja<br />

startup kôd treba da se prilagodi rešenju. Da bi učinili mogućim da se startup kôd može modifikovati<br />

najveći broj C kompajlera koji se nude na tržištu mogu automatski generisati kôd koji sadrži poseban fajl<br />

na asemblerskom jeziku u kome se nalazi startup kôd. Obično se ovaj fajl naziva crt0 ili crt1 (gde se<br />

crt odnosi na C Run Time). Ova mogućnost obezbeđuje projektantima da modifikuju startup kôd<br />

nezavisno od ostalih aktivnosti koje treba preduzeti.<br />

Na slici <strong>3.</strong>3 prikazan je dijagram toka funkcije crt0 za HP B3640 68K familiju C kroskompajler.


<strong>3.</strong>4.2 Run-time biblioteka<br />

Slika <strong>3.</strong>3 Funkcija crt0<br />

Najrestriktivnija definicija run-time biblioteke je sledeća: To je skup nevidljivih funkcija koje se<br />

koriste za podršku rada sistema kojim se pojednostavljuje generisanje kôda. Tako na primer, ako mašina<br />

ne poseduje hardver za podršku rada FP operacija, tada kompajler generiše poziv aritmetičkoj rutini koja<br />

je deo run-time biblioteke, svaki put kada se izvršava FP operacija. Smatrajmo da su rutine standardne C<br />

biblioteke deo run-time biblioteke. Eliminacijom funkcija run-time biblioteke koje se ne koriste, moguće<br />

je značajno redukovati obim programskog kôda kod embedded sistema. Takođe je moguće neke složene<br />

implementacije smanjiti uvođenjem prostih. Optimizacije (minimizacije obima kôda) se uobičajeno<br />

odnose na sledeće stavke:<br />

a) Podrška radu FP operacijama – ako ne postoji podrška za rad FP operacijama tada proizvođač<br />

kompajlera može da ponudi fixed-point biblioteku koja se može direktno pozivati.<br />

b) Podrška radu formatiranom izlazu (printf()) – umesto potpune podrške printf() funkciji,<br />

proizvođač može da ponudi funkcije za formatiranje specifičnih tipova kakve su, na primer,<br />

printIntAsHex(), printStr(), i druge.<br />

c) Podrška radu dinamičkoj alokaciji (ovo se odnosi na malloc() i funkciju HLL-a C++ kakva je<br />

new) – kako će projektant primeniti dinamičku alokaciju zavisi od mnogo faktora, a ne samo od<br />

dostupnog memorijskog prostora i hardverske podrške. U principu se dinamička alokacija ne<br />

koristi kod embedded sistema.<br />

<strong>3.</strong>5 Razmeštanje objekata<br />

Jasno je da projektanti embedded sistema treba da su u stanju da upravljaju fizičkom pozicijom<br />

(lokacijom) kôda i podataka u memoriji. Tako na primer, da bi kreirali tabelu vektora za obradu izuzetaka<br />

neophodno je da se kreira vektor ISR adresa i uslov da se početak tog vektora smesti na lokaciju 0. Na<br />

sličan način, programeri embedded sistema mora da su u stanju da smeste programske instrukcije na<br />

lokacijama gde se nalazi instaliran EPROM, a takođe da smeste globalne promenljive u adresni prostor<br />

gde se nalazi RAM. Slični izazovi postoje za startup kôd i ISR-ove.


Linker je primarno sredstvo (tool) koje se koristi za upravljanje razmeštajem kôda. U opštem<br />

slučaju, asembler kreira relokatibilne module koje linker "fiksira" na specifične fizičke adrese. Objasnimo<br />

sada šta znači pojam relokatibilni moduli i na koji način programeri embedded sistema mogu upravljati<br />

fizičkim razmeštajem objekata.<br />

<strong>3.</strong>5.1 Relokatibilni objekti<br />

Klasičan razvojni model embedded softvera je prikazan na slici <strong>3.</strong>4. Kao što se vidi sa slike <strong>3.</strong>4, C<br />

ili C++ izvorni fajl zajedno sa include fajlovima kompajliraju se od strane kompajlera u izvorni fajl na<br />

asemblerskom jeziku, a zatim asembler je taj koji kreira relokatibilni objektni fajl (modul).<br />

Slika <strong>3.</strong>4 Razvojni proces embedded softvera<br />

Kada asembler prevodi izvorne module u relokatibilne objektne module on manipuliše sadržajem<br />

internog brojača - nazvan lokacioni brojač - sa ciljem da čuva trag o granicama instrukcija (obim<br />

instrukcija izražen u bajtovima), relativno u odnosu na početnu adresu tog bloka. Na slici <strong>3.</strong>5 prikazan je<br />

deo kôda na asemblerskom jeziku mikroprocesora iz familije Motorola 68K.<br />

Slika <strong>3.</strong>5 Deo kôda na asemblerskom jeziku


Kao što se vidi sa slike <strong>3.</strong>5, brojač bajtova koji odgovara tekućoj vrednosti lokacionog brojača je<br />

osenčen. Brojač pokazuje na adresu instrukcije u ovom kôdnom bloku.<br />

Kod jednostavnih razvojnih okruženja, projektant koristi specijalne pseudo-instrukcije na<br />

asemblerskom jeziku kako bi razmestio objekte na pojedine lokacije, kao na primer, ORG 200H koja<br />

uslovljava da početna adresa modula bude 512.<br />

Kada se koriste HLL-ovi, za upravljanje razmeštajem, potrebno je koristiti neke druge<br />

mehanizme. Rešenje pozicioniranja sastoji se u tome da asembler generiše relokatibilne module. Pri tome,<br />

svaki relokatibilni modul se prevodi na takav način kao da počinje sa memorijske lokacije 0. Kada<br />

asembler pripremi modul, on takođe priprema simbol-tabelu koja pokazuje koje vrednosti u modulu treba<br />

promeniti ako se modul premesti na neku drugu lokaciju koja je različita od 0. Pre nego što se moduli<br />

load-uju radi izvršenja, linker ih relocira. Naime, linker podešava sve poziciono-osetljive vrednosti na<br />

takav način da budu odgovarajuće, tj. da pozicione vrednosti (adrese) odgovaraju stvarnoj poziciji modula<br />

u memoriji.<br />

Skupovi instrukcija savremenih procesora često sadrže specifično projektovane instrukcije koje<br />

pojednostavljuju posao linker-a, kao na primer, "jump-relative" instrukcije za koje nije potrebno<br />

podešavanje. Često kompajlerima i linker-ima ovih mašina se može narediti da generišu poziciononezavisne<br />

kodove, koji ne zahtevaju podešavanje, nezavisno od toga gde će se kôd smestiti u memoriji.<br />

Relokatibilni moduli (fajlovi) referenciraju (obraćaju se) funkcije u drugim modulima, tako da, na<br />

prvi pogled, postoji Pandorina kutija međusobno povezanih funkcijskih poziva i memorijskih<br />

referenciranja. Pored podešavanja internih referenciranja na aktuelne lokacije, linker je takođe zadužen za<br />

rešavanje ovih inter-modularnih referenciranja kao i kreiranje kôdnog bloka koji se može load-ovati na<br />

specifičnu lokaciju (memorijsku adresu) sistema.<br />

Kao zaključak bi mogli da kažemo sledeće:<br />

1) Relokatibilni moduli su važni iz više razloga. Ono što je najvažnije je to da prgramerima<br />

embedded sistema, relokatibilni moduli pojednostavljuju fizički razmeštaj kôda generisanog od<br />

strane HLL-a, i omogućavaju individualnim modulima da se nezavisno ažuriraju i kompajliraju.<br />

2) Kod sistema opšte-namene, relokatibilni moduli imaju tu dobru stranu da pojednostavljuju<br />

upravljanje memorijom (omogućavajući individualnim programima da se pune u bilo koju<br />

dostupnu memorijsku sekciju (deo) bez rekompilacije), kao i da olakšavaju korišćenje deljivih,<br />

unapred rekompajliranih biblioteka.<br />

<strong>3.</strong>5.2 Korišćenje linkera<br />

Ulazi u linker su: a) relokatibilni objektni moduli; i b) komandni fajl linker-a.<br />

Komandni fajl linker-a pruža projektantu mogućnost da u potpunosti kontroliše na koji će se način<br />

kôdni moduli međusobno povezati i kako se kreira konačna slika. Komandni fajl linker-a je ključni<br />

elemenat u ovom procesu i važan je diferencijator u odnosu na to kako se piše kôd za embedded sisteme<br />

ili kôd za desktop PC-ove, kao mašine opšte namene.<br />

Komandni fajl linker-a je korisničko kreirani tekstualni fajl koji ukazuje linker-u na koji način<br />

treba međusobno povezati relokatibilne fajlove. Linker-i koriste programske sekcije. Programska sekcija<br />

predstavlja kôdni-blok ili blok-podataka koji je logički različit u odnosu na druge sekcije i može se opisati<br />

svojim sopstvenim lokacionim brojačem. Sekcije imaju različite atribute koji ukazuju linker-u kako se ti<br />

atributi mogu koristiti. Tako na primer, sekcija može biti:<br />

• kôd programa<br />

• kôd podataka<br />

• mešavima kôda i podataka<br />

• podaci smešteni u ROM-u<br />

Listing na slici <strong>3.</strong>6 prikazuje tipične linker komande za mikroprocesore iz familije Motorola 68K,<br />

a značenje linker komandi je objašnjeno na slici <strong>3.</strong>7.


CHIP 68000<br />

LISTMAP INTERNALS, PUBLICS, CROSSREF<br />

COMMON COMSEC=$1000<br />

ORDER SECT2, SECT3, COMSEC<br />

PUBLIC EXTRANEOUS=$2000<br />

NAME TESTCASE<br />

PAGE SECT2<br />

FORMAT IEEE<br />

*LOAD-ovati prva dva modula<br />

LOAD Lnk68ka.obj, lnk68kb.obj<br />

*LOAD-ovati poslednji modul<br />

LOAD lnk68kc.obj<br />

END<br />

Slika <strong>3.</strong>6 Primer komandnog fajla linker-a<br />

CHIP Specificira ciljni mikroprocesor. Ova komanda određuje kako će se sekcije poravnjati sa<br />

tačke gledišta memorijskih adresnih granica, i u zavisnosti od specificiranog<br />

mikroprocesora, koliko je memorije dostupno. Konačno, ova komanda određuje<br />

ponašanje određenih procesorsko specifičnih adresnih načina rada.<br />

LISTMAP Generiše listing simbol-tabele kako za lokalne tako i eksterne simbol-definicije. Ova<br />

komanda takođe uzrokuje da se ovi simboli smeste u izlazni objektni modul tako da<br />

debager kasnije može simbolima da pridruži adrese. Simbol-tabela prikazuje simbole<br />

zajedno sa njihovim konačnim apsolutnim adresnim lokacijama. Moguće je zatim<br />

analizirati izlaz link-map-e i odrediti da li su svi moduli korektno povezani, kao i odrediti<br />

da li se nalaze u memoriji gde je projektant zamislio da trebaju biti. Kada linker uspešno<br />

obavi svoj zadatak, tada sve adrese su podešene na korektne konačne vrednosti, a takođe i<br />

COMMON;<br />

nazvan<br />

COMSEC<br />

svi link-ovi ili veze između modula su razrešeni.<br />

Smešten je na heksadecimalnoj početnoj adresi 1000 ($ označava heksadecimalnu<br />

vrednost). Linker smešta sve COMMON sekcije različitih modula sa istim imenom na<br />

istom mestu u memoriji. COMMON sekcije se u opštem slučaju koriste za programske<br />

promenljive koje se čuvaju u RAM-u, kao globalne promenljive.<br />

ORDER Specificira redosled po kome se sekcije zajednički povezuju u izvršivu image.<br />

PUBLIC Specificira apsolutnu adresu, heksadecimalnu 2000, za promenljivu EXTRANEOUS.<br />

NAME Specificira ime fajla konačnog izlaznog modula.<br />

TEST CASE<br />

PAGE Specificira da naredna sekcija počne na granici stranice, tj. da početna adresa bude<br />

multipl od 256. Nakon čitanja PAGE komande, svaka sub-sekcija, ili modul, specificirane<br />

sekcije se poravnjava na granicama stranice. U konkretnom primeru (slika <strong>3.</strong>6) SECT 2<br />

startovaće na narednoj dostupnoj granici stranice.<br />

FORMAT Specificira izlaz fajl formata. U konkretnom slučaju je to format IEEE-695, koji<br />

predstavlja standardni industrijski fajl format. Drugi format je Motorola S-Record fajl,<br />

koji je ASCII kôdirani fajl i čitljiv je od strane korisnika. Zapisi se uobičajeno koriste za<br />

punjenje kôda u uređaj za programiranje ROM-ova.<br />

LOAD Puni naredna tri specificirana objektna fajla.<br />

END Označava kraj objektnih fajlova.<br />

Slika <strong>3.</strong>7. Komande linker-a

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!