summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--os2w1/.gitignore2
-rw-r--r--os2w1/main.cpp28
-rw-r--r--os2w1/makefile17
-rw-r--r--os2w1/practicum.md291
4 files changed, 338 insertions, 0 deletions
diff --git a/os2w1/.gitignore b/os2w1/.gitignore
new file mode 100644
index 0000000..f0c9b81
--- /dev/null
+++ b/os2w1/.gitignore
@@ -0,0 +1,2 @@
+*.o
+main
diff --git a/os2w1/main.cpp b/os2w1/main.cpp
new file mode 100644
index 0000000..b7d4663
--- /dev/null
+++ b/os2w1/main.cpp
@@ -0,0 +1,28 @@
+#include <iostream>
+
+using namespace std;
+
+void show(int m, int n);
+void swap(int a, int b);
+
+int main() {
+ int a = 5;
+ int b = 7;
+
+ show(a, b);
+ swap(a, b);
+ show(a, b);
+
+ return 0;
+}
+
+void show(int m, int n) {
+ cout << "Getallen: " << m << ", " << n << endl;
+}
+
+void swap(int a, int b) {
+ int h;
+ h = a;
+ a = b;
+ b = h;
+}
diff --git a/os2w1/makefile b/os2w1/makefile
new file mode 100644
index 0000000..258d688
--- /dev/null
+++ b/os2w1/makefile
@@ -0,0 +1,17 @@
+CPP = g++
+LD = g++
+
+LFLAGS += -lstdc++
+CFLAGS += -g
+
+all: main
+
+main: main.o
+ $(LD) $^ $(LFLAGS) -o $@
+
+%.o: %.cpp
+ $(CPP) -c $(CFLAGS) $< -o $@
+
+clean:
+ $(RM) main.o main
+
diff --git a/os2w1/practicum.md b/os2w1/practicum.md
new file mode 100644
index 0000000..749facd
--- /dev/null
+++ b/os2w1/practicum.md
@@ -0,0 +1,291 @@
+# practicum week 1
+
+> ik heb de opdrachten met behulp van g++ als compiler en gdb als debugger
+> gemaakt, dus sommige registernamen of syntax kan mogelijk niet overeenkomen
+> met wat er verwacht wordt.
+
+## practicum setup
+
+```bash
+$ make
+g++ -c -g main.cpp -o main.o
+g++ main.o -lstdc++ -o main
+$ gdb main
+Reading symbols from main...
+(gdb) br main
+Breakpoint 1 at 0x1181: file main.cpp, line 9.
+(gdb) run
+Starting program: /home/loek/docs/repos/os-huiswerk/os2w1/main
+[Thread debugging using libthread_db enabled]
+Using host libthread_db library "/usr/lib/libthread_db.so.1".
+
+Breakpoint 1, main () at main.cpp:9
+9 int a = 5;
+(gdb)
+```
+
+## vraag 1
+
+In gdb heet EIP `$pc`, en deze heeft nadat het programma is gepauzeerd in de
+`main()` de hexadecimale waarde `0x555555555181`.
+
+```
+(gdb) print $pc
+$1 = (void (*)(void)) 0x555555555181 <main()+8>
+```
+
+## vraag 2
+
+`0x7fffffffcb20`:
+
+```
+(gdb) print $sp
+$2 = (void *) 0x7fffffffcb20
+```
+
+## vraag 3
+
+De door g++ gegenereerde machinecode bevat bij mij geen 200 bytes extra, en de
+initialisatie van de main functie is ook een stuk beknopter:
+
+```
+(gdb) disas /m main
+Dump of assembler code for function main():
+8 int main() {
+ 0x0000555555555179 <+0>: push rbp
+ 0x000055555555517a <+1>: mov rbp,rsp
+ 0x000055555555517d <+4>: sub rsp,0x10
+
+9 int a = 5;
+=> 0x0000555555555181 <+8>: mov DWORD PTR [rbp-0x8],0x5
+
+10 int b = 7;
+ 0x0000555555555188 <+15>: mov DWORD PTR [rbp-0x4],0x7
+
+11
+12 show(a, b);
+ 0x000055555555518f <+22>: mov edx,DWORD PTR [rbp-0x4]
+ 0x0000555555555192 <+25>: mov eax,DWORD PTR [rbp-0x8]
+ 0x0000555555555195 <+28>: mov esi,edx
+ 0x0000555555555197 <+30>: mov edi,eax
+ 0x0000555555555199 <+32>: call 0x5555555551c3 <_Z4showii>
+
+13 swap(a, b);
+ 0x000055555555519e <+37>: mov edx,DWORD PTR [rbp-0x4]
+ 0x00005555555551a1 <+40>: mov eax,DWORD PTR [rbp-0x8]
+ 0x00005555555551a4 <+43>: mov esi,edx
+ 0x00005555555551a6 <+45>: mov edi,eax
+ 0x00005555555551a8 <+47>: call 0x555555555234 <_Z4swapii>
+
+14 show(a, b);
+ 0x00005555555551ad <+52>: mov edx,DWORD PTR [rbp-0x4]
+ 0x00005555555551b0 <+55>: mov eax,DWORD PTR [rbp-0x8]
+ 0x00005555555551b3 <+58>: mov esi,edx
+ 0x00005555555551b5 <+60>: mov edi,eax
+ 0x00005555555551b7 <+62>: call 0x5555555551c3 <_Z4showii>
+
+15
+16 return 0;
+ 0x00005555555551bc <+67>: mov eax,0x0
+
+17 }
+ 0x00005555555551c1 <+72>: leave
+ 0x00005555555551c2 <+73>: ret
+
+End of assembler dump.
+```
+
+In de meegeleverde assembly wordt `ebp` - 216 in het `edi` register gezet. Deze
+waarde is de nieuwe stack pointer die na het volmaken van de nieuw gealloceerde
+ruimte in het echte stack pointer register gezet wordt.
+
+## vraag 4
+
+Omdat ik de c++ code heb gecompileerd met debug symbols kan gdb automatisch van
+`a` en `b` zien dat het 32-bits signed integers zijn, en gdb interpreteert
+automatisch de data op het adres van de variabelen op de "goede" manier.
+
+```
+(gdb) print $sp
+$1 = (void *) 0x7fffffffcb20
+(gdb) print &a
+$2 = (int *) 0x7fffffffcb28
+(gdb) print &b
+$3 = (int *) 0x7fffffffcb2c
+(gdb) info locals
+a = -137244042
+b = 32767
+```
+
+## vraag 5
+
+```
+(gdb) br main.cpp:12
+Breakpoint 2 at 0x55555555518f: file main.cpp, line 12.
+(gdb) c
+Continuing.
+
+Breakpoint 2, main () at main.cpp:12
+12 show(a, b);
+(gdb) info locals
+a = 5
+b = 7
+(gdb) x &a
+0x7fffffffcb28: 0x00000005
+(gdb) x &b
+0x7fffffffcb2c: 0x00000007
+```
+
+## vraag 6
+
+Aan het einde van de `swap()` functie zijn de waardes van `a` en `b` (lokaal
+tot de `swap()` functie) daadwerkelijk aangepast. Dit zijn alleen niet dezelfde
+`a` en `b` als in de `main()` functie, dus lijkt het alsof er niks is gebeurt
+na de return instructie.
+
+```
+(gdb) disas /m swap
+Dump of assembler code for function _Z4swapii:
+23 void swap(int a, int b) {
+ 0x0000555555555234 <+0>: push rbp
+ 0x0000555555555235 <+1>: mov rbp,rsp
+ 0x0000555555555238 <+4>: mov DWORD PTR [rbp-0x14],edi
+ 0x000055555555523b <+7>: mov DWORD PTR [rbp-0x18],esi
+
+24 int h;
+25 h = a;
+ 0x000055555555523e <+10>: mov eax,DWORD PTR [rbp-0x14]
+ 0x0000555555555241 <+13>: mov DWORD PTR [rbp-0x4],eax
+
+26 a = b;
+ 0x0000555555555244 <+16>: mov eax,DWORD PTR [rbp-0x18]
+ 0x0000555555555247 <+19>: mov DWORD PTR [rbp-0x14],eax
+
+27 b = h;
+ 0x000055555555524a <+22>: mov eax,DWORD PTR [rbp-0x4]
+ 0x000055555555524d <+25>: mov DWORD PTR [rbp-0x18],eax
+
+28 }
+=> 0x0000555555555250 <+28>: nop
+ 0x0000555555555251 <+29>: pop rbp
+ 0x0000555555555252 <+30>: ret
+
+End of assembler dump.
+(gdb) print a
+$1 = 7
+(gdb) print b
+$2 = 5
+```
+
+## vraag 7
+
+Ik zie dat er nu voor elke toewijzing van `a`, `b`, en `h` een extra instructie
+die het `rax` register gebruikt is toegevoegd. Ik zie ook dat het adres voor
+`a` en `b` in de scope van de `main()` functie nu hetzelfde is als die binnen
+de `swap()` functie.
+
+```
+(gdb) disas /m swap
+Dump of assembler code for function _Z4swapRiS_:
+23 void swap(int &a, int &b) {
+ 0x000055555555526b <+0>: push rbp
+ 0x000055555555526c <+1>: mov rbp,rsp
+ 0x000055555555526f <+4>: mov QWORD PTR [rbp-0x18],rdi
+ 0x0000555555555273 <+8>: mov QWORD PTR [rbp-0x20],rsi
+
+24 int h;
+25 h = a;
+ 0x0000555555555277 <+12>: mov rax,QWORD PTR [rbp-0x18]
+ 0x000055555555527b <+16>: mov eax,DWORD PTR [rax]
+ 0x000055555555527d <+18>: mov DWORD PTR [rbp-0x4],eax
+
+26 a = b;
+=> 0x0000555555555280 <+21>: mov rax,QWORD PTR [rbp-0x20]
+ 0x0000555555555284 <+25>: mov edx,DWORD PTR [rax]
+ 0x0000555555555286 <+27>: mov rax,QWORD PTR [rbp-0x18]
+ 0x000055555555528a <+31>: mov DWORD PTR [rax],edx
+
+27 b = h;
+ 0x000055555555528c <+33>: mov rax,QWORD PTR [rbp-0x20]
+ 0x0000555555555290 <+37>: mov edx,DWORD PTR [rbp-0x4]
+ 0x0000555555555293 <+40>: mov DWORD PTR [rax],edx
+
+28 }
+ 0x0000555555555295 <+42>: nop
+ 0x0000555555555296 <+43>: pop rbp
+ 0x0000555555555297 <+44>: ret
+
+End of assembler dump.
+```
+
+## vraag 8
+
+```
+(gdb) disas recursief
+Dump of assembler code for function _Z9recursiefi:
+ 0x0000000000001189 <+0>: push rbp
+ 0x000000000000118a <+1>: mov rbp,rsp
+ 0x000000000000118d <+4>: sub rsp,0x10
+ 0x0000000000001191 <+8>: mov DWORD PTR [rbp-0x4],edi
+ 0x0000000000001194 <+11>: mov eax,DWORD PTR [rbp-0x4]
+ 0x0000000000001197 <+14>: sub eax,0x1
+ 0x000000000000119a <+17>: mov edi,eax
+ 0x000000000000119c <+19>: call 0x1189 <_Z9recursiefi>
+ 0x00000000000011a1 <+24>: mov edx,DWORD PTR [rbp-0x4]
+ 0x00000000000011a4 <+27>: add eax,edx
+ 0x00000000000011a6 <+29>: leave
+ 0x00000000000011a7 <+30>: ret
+End of assembler dump.
+```
+
+Op regel drie van de disassembly is een `sub rsp,0x10` instructie te zien, die
+16 bytes van de stack pointer afhaalt (16 bytes allocatie). Deze bytes zullen
+waarschijnlijk komen door 4 bytes voor het argument dat `recursief` weer
+meegegeven wordt bij de volgende aanroep, 4 bytes padding, 4 bytes voor de
+return waarde en weer 4 bytes padding.
+
+## vraag 9
+
+Ik heb het volgende programma geschreven om te testen hoe groot de stack kan
+worden voordat het programma zichzelf laat crashen:
+
+```c
+volatile unsigned long i = 0;
+
+void rec() {
+ i++;
+ rec();
+}
+
+int main() {
+ rec();
+ return 0;
+}
+```
+
+Ik heb het programma een paar keer uitgevoerd onder een debugger om de
+uiteidenlijke waarde van `i` te inspecteren, en er kwam altijd een waarde rond
+523700 (decimaal) uit. Deze functie reserveert geen lokale stack variabelen:
+
+```
+(gdb) disas rec
+Dump of assembler code for function _Z3recv:
+ 0x0000000000001119 <+0>: push rbp
+ 0x000000000000111a <+1>: mov rbp,rsp
+ 0x000000000000111d <+4>: mov rax,QWORD PTR [rip+0x2ef4] # 0x4018 <i>
+ 0x0000000000001124 <+11>: add rax,0x1
+ 0x0000000000001128 <+15>: mov QWORD PTR [rip+0x2ee9],rax # 0x4018 <i>
+ 0x000000000000112f <+22>: call 0x1119 <_Z3recv>
+ 0x0000000000001134 <+27>: nop
+ 0x0000000000001135 <+28>: pop rbp
+ 0x0000000000001136 <+29>: ret
+End of assembler dump.
+```
+
+Zonder het reserveren van stackruimte per aanroep, kost elke aanroep alleen nog
+8 bytes voor het return adres. De maximale stack grootte zal dan ongeveer 4 MB
+zijn. De eerdere `recursief()` functie kost in totaal 32 bytes per aanroep (16
+voor lokale variabelen, 8 voor return adres en nog 8 voor return waarde). Dat
+zou betekenen dat de `recursief()` functie na ongeveer 130000 keer de stack
+overvol zou maken.
+