Системски софтвер/Август 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. задатак

Поставка

Посматра се процес покренут над програмом 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, наведен у наставку, потребно је урадити следеће.

  1. [2] Одредити на којој адреси се налази .got.plt секција програма run.
  2. [4] Попунити .plt секцију (заменити свако појављивање знакова питања одговарајућом вредношћу) уколико је познато да се улаз за функцију bar унутар .plt секције налази испред улаза за функцију baz унутар .plt секције.
  3. [2] Навести вредности које се налазе у улазима .got.plt секције, који одговарају симболима bar и baz, у тренутку пре него што је посматрани процес извршио први позив било које функције из дељене библиотеке libfoo.so.
  4. [2] Навести вредности које се налазе у улазима .got.plt секције, који одговарају симболима bar и baz, у тренутку након што је посматрани процес извршио позив функције bar, а пре позива функције baz.
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 ?? ?? ?? ??                jmp QWORD PTR [rip + ??]
  1076: 68 00 00 00 00                   push 0x00
  107b: e9 ?? ?? ?? ??                   jmp ??
  1080: ff 25 ?? ?? ?? ??                jmp QWORD PTR [rip + ??]
  1086: 68 01 00 00 00                   push 0x01
  108b: e9 ?? ?? ?? ??                   jmp ??

Решење

Адресу .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