Системски софтвер/Август 2022

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

Испит у августовском року 2022. године одржан је 24. августа. Сваки задатак вреди укупно 10 поена. Испит траје 2 сата.

1. задатак

Поставка

Одредити вредност при обради од стране асемблера за хипотетичку машину (уколико вредност није позната написати знак питања) и индекс класификације за сваки израз у оквиру изворног асемблерског кода датог у наставку.

        BEG
        USE LAB1
        ORG 0x60
        SCT DAT
LAB2    DC LAB1
        DC 7 + LAB2
        SCT TXT
LAB3    LDA LAB2 - 1
        ADX * - LAB3
        END

Решење

Наредба Индекс класификације Вредност
DC LAB1 1.unique() ?
DC 7 + LAB2 0 + 1.DAT = 1.DAT 0x67
LDA LAB2 - 1 1.DAT - 0 = 1.DAT 0x5f
ADX * - LAB3 1.TXT - 1.TXT = 0 0x2

2. задатак

Поставка

Навести шта је резултат експанзије следећег кода од стране C претпроцесора и објаснити како је добијен.

#define M1(x1) M2(x1)
#define M2(x1) M3(x1,A)
#define M3(x1,x2) x2 M3(x1,x2) M1(x1)
M3(M1(C), B)

Решење

Појављивање неког макроа у својој дефиницији се не сматра макропозивом. Видети 3.10.5 Self-Referential Macros из документације C претпроцесора.

B M3(A M3(C, A) M1(C), B) M3(A M3(C,A) M1(C), A)

3. задатак

Поставка

За неки емулатор потребно је написати функцију void write(unsigned addr, unsigned data) за упис у меморију. Адресни простор је величине 4 GB, а адресабилна јединица је бајт. Сматрати да је приступ речи увек поравнат на адресу дељиву са 4. На располагању су функције unsigned rphy(unsigned addr), која дохвата реч са дате физичке адресе и void wphy(unsigned addr, unsigned data), која уписује задату реч на задату физичку адресу. Емулирана машина поседује виртуелну меморију организовану странично. Величина странице је 16 KB. Регистар PMTP (који се емулира истоименом глобалном променљивом) садржи адресу табеле за пресликавање страница. Сваки улаз у табели је 32 бита, при чему су највиша два бита V и D битови. Уколико је V бит једнак 0, у најнижих 30 битова је записана адреса на диску, док је у случају да је бит V једнак 1, у најнижим битовима улаза записан редни број блока у који је смештена страница. У случају да страница није у меморији, учитава се у меморију позивом функције void load(unsigned hddaddr), која у позадини генерише page fault и блокира позивајућу нит док страница не буде учитана са диска. Једини аргумент функције представља адресу којој се приступа.

Решење

Адресни простор је 4 GB, што значи да је адреса 32-битна. Ако је величина странице 16 KB, најнижих 14 бита виртуелне адресе је померај у страници, а виших 18 је број улаза. Пошто је свака реч поравната са 4, улаз у табелу не мора да садржи два најнижа бита јер су она увек 0. Улаз у табелу пресликавања страница и виртуеална адреса изгледају овако:

VA(32): PageNumber(18), Offset(14)

PMT(32): V(1), D(1), PhyAddress/BlockNumber(30)

void write(unsigned addr, unsigned data) {
    unsigned offset = addr & 0x3FFF;
    unsigned blk_no = addr >> 14;
    // Проверавамо присутност блока у меморији
    if (PMTP[blk_no] & 0x8000_0000) {
        // Блок се налази у меморији
        unsigned phy_addr = PMT[blk_no] << 2;
        wphy(phy_addr + offset, data);

        // Постављање dirty бита није било стриктно тражено на испиту
        PMTP[blk_no] |= 0x4000_0000;
    } else {
        // Блок се мора довући са диска
        unsigned block_no = PMT[blk_no] & 0x3FFF_FFFF;
        load(block_no);
        // Рекурзивни позив упада у горњу грану if-а.
        write(addr, data);
    }
}

4. задатак

Поставка[1]

Посматра се процес покренут над програмом run добијеним повезивањем са дељеном библиотеком libfoo.so. Дељена библиотека libfoo.so садржи функције bar и baz чије су адресе унутар libfoo.so 0x1218 и 0x12C4 респективно, а сама дељена библиотека libfoo.so мапирана је почев од адресе 0x4FFF0000 унутар адресног простора посматраног процеса.

Програм run, који представња PIC shared object ELF датотеку, мапиран је почев од адресе 0x7EEE0000 унутар адресног простора посматраног процеса. Програм run од дељених библиотека користи искључиво libfoo.so и позива њене две функције bar и baz користећи лењо повезивање. Уколико је познат део .plt секције програма run, наведен у наставку, потребно је урадити следеће.

Disassembly of section .plt:
0000000000001060 <.plt>:
  1060: push QWORD PTR [rip + 0x42a2]
  1066: jmp QWORD PTR [rip + 0x42a4]
  106c: nop DWORD PTR [rax + 0x00]
  1070: jmp QWORD PTR [rip + ??]
  1076: push 0x00
  107b: jmp ??
  1080: jmp QWORD PTR [rip + ??]
  1086: push 0x01
  108b: jmp ??
  1. Адреса на којој се налази почетак .got.plt секције програма run је 7EEE5300.[2]
  2. Вредност ??1 је 000042A2.
  3. Вредност ??2 је 0000429A.
  4. Померај инструкције скока jmp на адреси 0x107b је FFFFFFE0
  5. Померај инструкције скока jmp на адреси 0x108b је FFFFFFD0
  6. Вредност улаза у .got.plt секцији, који одговара симболу bar, у тренутку пре него што је посматрани процес извршио први позив било које функције из дељене библиотеке libfoo.so је 7EEE1076
  7. Вредност улаза у .got.plt секцији, који одговара симболу baz, у тренутку пре него што је посматрани процес извршио први позив било које функције из дељене библиотеке libfoo.so је 7EEE1086
  8. Вредност улаза у .got.plt секцији, који одговара симболу bar, у тренутку након што је посматрани процес извршио позив функције baz, а пре позива функције bar је 7EEE1076
  9. Вредност улаза у .got.plt секцији, који одговара симболу baz, у тренутку након што је посматрани процес извршио позив функције baz, а пре позива функције bar је 4FFF12C4

Решење

Адресу .got.plt секције може се наћи разрешавањем помераја у нултом улазу .plt секције. Инструкција push на 0x1060 као операнд има први улаз у GOT табели. Величина улаза у GOT табели је 8 бајта. Одатле:

GOT[1] = rip + 0x42a2
GOT[1] = 0x1066 + 0x42a2
GOT[1] = 0x5308
GOT[0] = GOT[1] - 1 * 8 = 0x5308 - 8 = 0x5300

Исти резултат се добија коришћењем операнда jmp инструкције на 0x1066, која указује на други улаз:

GOT[2] = rip + 0x42a4
GOT[2] = 0x106c + 0x42a4
GOT[2] = 0x5310
GOT[0] = GOT[2] - 2 * 8 = 0x5310 - 0x10 = 0x5300

Структура GOT табеле:

Адреса Улаз Садржај
0x5300
0 .dynamic
0x5308 1 .rel.dyn
0x5310 2 динамички линкер
0x5318 3 bar()
0x5320 4 baz()

Први улаз PLT-а припада функцији bar. Инструкција jmp на 0x1070 треба да скаче на трећи улаз у GOT, а jmp на 0x107b на нулти улаз PLT-а:

0x5318 - 0x1076 = 0x42a2
0x1060 - 0x1080 = 0xffffffe0

Други улаз PLT-а припада функцији baz. Инструкција jmp на 0x1080 треба да скаче на четврти улаз у GOT, а jmp на 0x108b на нулти улаз PLT-а:

0x5320 - 0x1086 = 0x429a
0x1060 - 0x1090 = 0xffffffd0

Садржај .plt секције:

Disassembly of section .plt:
0000000000001060 <.plt>:
  1060: ff 35 a2 42 00 00                push QWORD PTR [rip + 0x42a2]
  1066: ff 25 a4 42 00 00                jmp QWORD PTR [rip + 0x42a4]
  106c: 0f 1f 40 00                      nop DWORD PTR [rax + 0x00]
  1070: ff 25 a2 42 00 00                jmp QWORD PTR [rip + 0x42a2]
  1076: 68 00 00 00 00                   push 0x00
  107b: e9 e0 ff ff ff                   jmp 1060
  1080: ff 25 9a 42 00 00                jmp QWORD PTR [rip + 0x429a]
  1086: 68 01 00 00 00                   push 0x01
  108b: e9 d0 ff ff ff                   jmp 1060

Садржај GOT табеле пре позивања било које функције из libfoo.so:

  5318: 76 10 ee 7e 00 00 00 00
  5320: 86 10 ee 7e 00 00 00 00

Садржај GOT табеле након што је посматрани процес извршио позив функције bar, а пре позива функције baz:

  5318: 18 12 ff 4f 00 00 00 00
  5320: 86 10 ee 7e 00 00 00 00
  

Напомене

  1. Поставка је измењена да одговара Мулд формату, иако у овом року испит није полаган путем рачунара, зарад боље припреме студената и избегавања понављања истог садржаја.
  2. Након жалби је признаван и само одговор 5300