Системски софтвер/Јун 2022

Извор: SI Wiki
Пређи на навигацију Пређи на претрагу

Испит у јунском испитном року 2022. године одржан је 16. јуна. Трајао је 2 сата и радио се у вежбанкама.

1. задатак

Поставка

Посматра се процес асемблирања датог ивзорног асемблерског кода за amd64 архитектуру. Резултат асемблирања је предметни програм по ELF формату. Приказати садржај (1) табеле симбола и (2) релокационих записа строго поштујући школски формат и обавезно у складу са задатом нумерацијом симбола.

.intel_syntax noprefix
.section .text
.global min, la1
min: enter 0, 0          # 0x00
     mov rbx, la1        # 0x04
     cmp rbx, [rbp]+0x12 # 0x0c
     call var[rip]       # 0x10
     jle la1             # 0x16
     mov rax, [rbp]+0x12 # 0x18
     jmp la2             # 0x1c
la1: mov rax, rbx        # 0x1e
la2: leave               # 0x21
     ret                 # 0x22

.data
.global var
.type var, @object
var:
.quad la1, la2-4
.end

Напомена: хексадецимални бројеви наведени у коментару изворног асемблерског кода представљају померај до почетка инструкције у том реду гледано од почетка секције којој инструкција припада. Такође, усвојити претпоставку да је величина операционог кода:

  • 2B за инструкцију call за PC релативно адресирање,
  • 4B за инструкцију mov за апсолутно адресирање и
  • 1B за инструкције jle и jmp за PC релативно адресирање.

Решење

.symtab
Num Value Size Type Bind Ndx Name
0: 0 0 NOTYP LOC UND
1: 0 0 SCTN LOC 1 .text
2: 0 0 SCTN LOC 2 .data
3: 0 0 SCTN LOC 3 .bss
4: 21 0 NOTYP LOC 1 la2
5: 0 0 NOTYP GLOB 1 min
6: 1E 0 NOTYP GLOB 1 la1
7: 0 0 OBJ GLOB 2 var

Иако није приказано у школском формату, симболи означени преко .type simbol, @object имају тип OBJECT у GNU асемблеру.

.rela.text
Offset Type Symbol Addend
8 R_X86_64_32 6 (la1) 0
12 R_X86_64_PC32 7 (var) -4
17 R_X86_64_PC8 6 (la1) -1
1D R_X86_64_PC8 1 (.text) 20

Релокациони записи на 17 и 1D не морају да постоје, пошто се померај може уградити и током асемблирања.

.rela.data
Offset Type Symbol Addend
0 R_X86_64_64 6 (la1) 0
8 R_X86_64_64 1 (.text) 1D

2. задатак

Поставка

У C претпроцесору треба написати макри дефиницију REPEAT(str, n) која као свој резултат даје стринг str надовезан n пута на самог себе за вредности параметра n између 0 и 5. На пример, макро позив REPEAT("ha ", 3) резултује стрингом "ha ha ha ". Треба имати на уму да C претпроцесор не дозвољава рекурзију (макро не може рекурзивно позвати самог себе) нити дозвољава коришћење #if у телу макроа.

Решење

#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)

При позиву REPEAT("ha ", 3) макропроцесор ће генерисати "ha " "ha " "ha " што је еквивалентно стрингу "ha ha ha " (тако функционише конкатенација стринг литерала у C). Ово понашање је било напоменуто на испиту.

3. задатак

Поставка

Задати модули main.c и other.c одвојено се преводе и потом статички повезују у јединствену извршну датотеку помоћу GNU ланца алата. Приликом повезивања не користе се други модули нити библиотеке. Треба попунити сваки од коментара /* ??? */ у датотеци other.c једном од наведених ознака које дефинишу какав ефекат изазива декларација која претходи коментару на датој линији:

  • OK-GLB: ово је исправна декларација променљиве која је глобална и за main.c и за other.c (глобална у смислу да ће се промена коју направи foo() функција коректно рефлектовати и у main() функцији као и обрнуто),
  • OK-LOC: ово је исправна декларација променљиве која је локална само за foo() (локална у смислу да се било која промена коју направи foo() функција неће рефлектовати на main() функцију),
  • CMPL_E: ова декларација ће изазвати пријаву грешке од стране преводиоца (линкер неће бити ни покренут),
  • LINK_E: ова декларација ће изазвати пријаву грешке од стране линкера (обе датотеке биће преведене без грешке, али линкер ће пријавити грешку приликом повезивања на симболу на датој линији),
  • SMNT_E: ова декларација неће изазвати пријаву никакве грешке (ни преводиоца нити линкера), али ће програм имати семантичку грешку односно логичку неисправност која се може манифестовати током његовог извршавања и
  • OTHR_E: дешава се нека друга грешка која није покривена претходним случајевима.
// 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() {
  // ...
}

Решење

main.c other.c Класификација

extern int a;

double a;

SMNT_E

static double b;

double b;

OK-LOC

int help; int *c = &help;

int *c;

OK-GLB
struct
{
  double d;
double d;
OK-LOC

} e;

int e = 0;

SMNT_E

int f = 0;

int f;

OK-GLB

double g = 0.1;

double g = 0.1;

LINK_E

#define h 99

int h = 99;

OK-LOC

int i;

unsigned *i;

SMNT_E

unsigned j;

static int j;

OK-LOC

4. задатак

Поставка

Посматра се JIT емулатор и емулирање следећег програма.

  1. Означити све блокове који ће у току рада емулатора бити преведени. За сваки преведени блок навести јединствену идентификацију у облику B<n>(<x>-<y>) (<n> је редни број блока у погледу тренутка његовог превођења при чему нумерација почиње од броја један, <x> је редни број прве а <y> редни број последње линије изворног кода блока).
  2. Навести секвенцу извршавања. У секвенци извршавања могу се нађи само GP (сваки пут када се емулатор врати у главну петљу), BH (сваки пут када се позове функција која помаже у разрешавању скокова) и B<n> (сваки пут када се изврши дати блок у складу са ознакама из претходне тачке).
      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

Решење

  1. Блокови по редоследу додавања у табелу (B3 је додат у табелу док још није био преведен):
    1. B0(1-5)
    2. B1(4-5)
    3. B2(6-6)
    4. B3(9-9)
    5. B4(7-8)
    6. B5(3-3)
  2. Редослед извршавања:
    1. GP
    2. B0
    3. BH
    4. GP
    5. B1
    6. BH (уколико се приликом превођења B1 није извршила оптимизација да се уместо branch helper угради скок на B1)
    7. B1
    8. B1
    9. BH
    10. GP
    11. B2
    12. BH
    13. GP
    14. B4
    15. BH
    16. GP
    17. B5
    18. B1
    19. B1
    20. B1
    21. B1
    22. B1
    23. BH
    24. B2
    25. BH
    26. GP
    27. B3
    28. BH
    29. GP