Системски софтвер/Август 2022
Испит у августовском року 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, наведен у наставку, потребно је урадити следеће.
- [2] Одредити на којој адреси се налази
.got.plt
секција програма run. - [4] Попунити
.plt
секцију (заменити свако појављивање знакова питања одговарајућом вредношћу) уколико је познато да се улаз за функцијуbar
унутар.plt
секције налази испред улаза за функцијуbaz
унутар.plt
секције. - [2] Навести вредности које се налазе у улазима
.got.plt
секције, који одговарају симболимаbar
иbaz
, у тренутку пре него што је посматрани процес извршио први позив било које функције из дељене библиотеке libfoo.so. - [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