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