Sistemski softver/Jun 2022
Ispit u junskom ispitnom roku 2022. godine održan je 16. juna. Trajao je 2 sata i radio se u vežbankama.
1. zadatak
Postavka
Posmatra se proces asembliranja datog ivzornog asemblerskog koda za amd64 arhitekturu. Rezultat asembliranja je predmetni program po ELF formatu. Prikazati sadržaj (1) tabele simbola i (2) relokacionih zapisa strogo poštujući školski format i obavezno u skladu sa zadatom numeracijom simbola.
.intel_syntax noprefix
.extern a
.global f
.type f, @object
.equ f, b-c
.text
call a[+ip] # 0x00
e: mov rax, c # 0x06
jz e # 0x0e
jz c # 0x10
d: mov rax, [b - f] # 0x16
.long e # 0x1e
.data
.skip 0x6 # 0x00
c: .long b + 0xe # 0x06
b:
.end
Napomena: Heksadecimalni brojevi navedeni u komentaru izvornog asemblerskog koda predstavljaju pomeraj do početka instrukcije u tom redu gledano od početka sekcije kojoj instrukcija pripada. Takođe, usvojiti pretpostavku da je veličina operacionog koda:
- 2B za instrukciju
callza PC relativno adresiranje, - 4B za instrukciju
movza apsolutno adresiranje i - 2B ili 1B za instrukcije skoka za PC relativno adresiranje, u zavisnosti od širine operanda.
Rešenje
2. zadatak
Postavka
U C pretprocesoru treba napisati makri definiciju REPEAT(str, n) koja kao svoj rezultat daje string str nadovezan n puta na samog sebe za vrednosti parametra n između 0 i 5. Na primer, makro poziv REPEAT("ha ", 3) rezultuje stringom "ha ha ha ". Treba imati na umu da C pretprocesor ne dozvoljava rekurziju (makro ne može rekurzivno pozvati samog sebe) niti dozvoljava korišćenje #if u telu makroa.
Rešenje
#define REP0(X)
#define REP1(X) X
#define REP2(X) REP1(X) X
#define REP3(X) REP2(X) X
#define REP4(X) REP3(X) X
#define REP5(X) REP4(X) X
#define REPEAT(str, n) REP##n(str)
Pri pozivu REPEAT("ha ", 3) makroprocesor će generisati "ha " "ha " "ha " što je ekvivalentno stringu "ha ha ha " (tako funkcioniše konkatenacija string literala u C). Ovo ponašanje je bilo napomenuto na ispitu.
3. zadatak
Postavka
Zadati moduli main.c i other.c odvojeno se prevode i potom statički povezuju u jedinstvenu izvršnu datoteku pomoću GNU lanca alata. Prilikom povezivanja ne koriste se drugi moduli niti biblioteke. Treba popuniti svaki od komentara /* ??? */ u datoteci other.c jednom od navedenih oznaka koje definišu kakav efekat izaziva deklaracija koja prethodi komentaru na datoj liniji:
OK-GLB: ovo je ispravna deklaracija promenljive koja je globalna i za main.c i za other.c (globalna u smislu da će se promena koju napravifoo()funkcija korektno reflektovati i umain()funkciji kao i obrnuto),OK-LOC: ovo je ispravna deklaracija promenljive koja je lokalna samo zafoo()(lokalna u smislu da se bilo koja promena koju napravifoo()funkcija neće reflektovati namain()funkciju),CMPL_E: ova deklaracija će izazvati prijavu greške od strane prevodioca (linker neće biti ni pokrenut),LINK_E: ova deklaracija će izazvati prijavu greške od strane linkera (obe datoteke biće prevedene bez greške, ali linker će prijaviti grešku prilikom povezivanja na simbolu na datoj liniji),SMNT_E: ova deklaracija neće izazvati prijavu nikakve greške (ni prevodioca niti linkera), ali će program imati semantičku grešku odnosno logičku neispravnost koja se može manifestovati tokom njegovog izvršavanja iOTHR_E: dešava se neka druga greška koja nije pokrivena prethodnim slučajevima.
// file main.c
extern int a;
static double b;
int help; int *c = &help;
struct
{
double d;
} e;
int f = 0;
double g = 0.1;
#define h 99
int i;
unsigned j;
int main() {
// ...
}
// file other.c
double a; /* ??? */
double b; /* ??? */
int *c; /* ??? */
double d; /* ??? */
int e = 0; /* ??? */
int f; /* ??? */
double g = 0.1; /* ??? */
int h = 99; /* ??? */
unsigned *i; /* ??? */
static int j; /* ??? */
int foo() {
// ...
}
Rešenje
main.c
|
other.c
|
Klasifikacija |
|---|---|---|
|
|
|
SMNT_E |
|
|
|
OK-LOC |
|
|
|
OK-GLB |
struct
{
double d;
|
double d;
|
OK-LOC |
|
|
|
SMNT_E |
|
|
|
OK-GLB |
|
|
|
LINK_E |
|
|
|
OK-LOC |
|
|
|
SMNT_E |
|
|
|
OK-LOC |
4. zadatak
Postavka
Posmatra se JIT emulator i emuliranje sledećeg programa.
- Označiti sve blokove koji će u toku rada emulatora biti prevedeni. Za svaki prevedeni blok navesti jedinstvenu identifikaciju u obliku
B<n>(<x>-<y>)(<n>je redni broj bloka u pogledu trenutka njegovog prevođenja pri čemu numeracija počinje od broja jedan, <x> je redni broj prve a <y> redni broj poslednje linije izvornog koda bloka). - Navesti sekvencu izvršavanja. U sekvenci izvršavanja mogu se nađi samo
GP(svaki put kada se emulator vrati u glavnu petlju),BH(svaki put kada se pozove funkcija koja pomaže u razrešavanju skokova) iB<n>(svaki put kada se izvrši dati blok u skladu sa oznakama iz prethodne tačke).
BEG ; line 1
LDI 2 ; line 2 ( PZ) A <= <V>
L1 SUB B ; line 3 (CPZ) A <= A - mem[<V>]
L2 ADD C ; line 4 (CPZ) A <= A + mem[<V>]
BNG L2 ; line 5 if (!flags[P]) PC <= <V>
BZE L3 ; line 6 if ( flags[Z]) PC <= <V>
SBI 2 ; line 7 (CPZ) A <= A - <V>
BNZ L1 ; line 8 if (!flags[Z]) PC <= <V>
L3 HLT ; line 9 stop execution
B DC 9 ; line 10
C DC 2 ; line 11
END ; line 12
Rešenje
- Blokovi po redosledu dodavanja u tabelu (B3 je dodat u tabelu dok još nije bio preveden):
- B0(1-5)
- B1(4-5)
- B2(6-6)
- B3(9-9)
- B4(7-8)
- B5(3-3)
- Redosled izvršavanja:
- GP
- B0
- BH
- GP
- B1
- BH (ukoliko se prilikom prevođenja B1 nije izvršila optimizacija da se umesto branch helper ugradi skok na B1)
- B1
- B1
- BH
- GP
- B2
- BH
- GP
- B4
- BH
- GP
- B5
- B1
- B1
- B1
- B1
- B1
- BH
- B2
- BH
- GP
- B3
- BH
- GP