# Lista 6 (15 kwietnia 2021), grupa KBa ###### tags: `ask21` `ćwiczenia` `kba` ## Deklaracje Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie (co najwyżej jedno!) w trakcie dyskusji oznacz je znakiem ==X== na żółtym tle. **UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!** :::danger | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8(B) | | --------------------:| --- | --- | --- | --- | --- | --- | --- | ---- | | Andriy Bernad | X | X | X | X | | X | | | 5 | Wojciech Bogucki | X | X | | X | | X | | | 4 | Michał Doros | X | X | | X | X | X | X | | 6 | Marko Golovko | X | X | | | | | | | 2 | Magdalena Jarecka | | | | | | | | | 0 | Szymon Jędras | X |==X==| | X | X | X | | | 5 | Heorhii Karpenko | X | X | X | X | | X | | | 5 | Szymon Kosakowski | X | X | X | | X | X | | | 5 | Izabella Kozioł | | | | | | | | | 0 | Franciszek Malinka | X | X | | X | | X | X | | 5 | Filip Pazera | X | X | | X | | X | | | 4 | Franciszek Pindel | X | X | X | X | | X | X | | 6 | Kacper Puchalski | X | X | X | | | X | | | 4 | Kacper Solecki | X | X | | X | | X | X | | 5 | Andrzej Tkaczyk | X | X | | X | | X | X | | 5 | Łukasz Wasilewski | | x | x | x | x | x | | | 5 | Vladyslav Yablonskyi | X | X | X | | | X | | | 4 | Adam Zyzik | X | | | X | | X | | | 3 ::: ## Zadanie 1 :::info Autor: Adam Zyzik ::: ![](https://i.imgur.com/yt96GuO.png) ```c= long puzzle(long n, long *p) { long result = 0; if(n > 0) { long temp; puzzle(2 * n, &temp); result += temp; n += result; } *p = n; return result; } ``` Rekord aktywacji: * adres powrotu (chyba że zaliczamy go poprzedniej ramki) * poprzednia wartość **%rbp** * poprzednia wartośc **%rbx** * puste 8 bajtów * zmienna lokalna **temp** * puste 8 bajtów Calee-saved registers: **%rbx**, **%rbp** Zmienne lokalne: **temp** ## Zadanie 2 :::info Autor: Szymon Jędras ::: ![](https://i.imgur.com/GkmwRdv.png) ```=c struct T{ long max; long min; long average; }; struct T puzzle8(long* a, long n){ // wskaznik na ret jest przekazany funkcji w rdi // wiec argumenty zaczynają sie od rsi zatem: // rsi = a, rdx = n struct T result; long sum = 0; long max = LONG_MIN; long min = LONG_MAX; // i jest przechowywane w r10 for(int i = 0; i < n; i++) { if(min < a[i]) min = a[i]; if(max > a[i]) max = a[i]; sum += a[i]; } // po wyjściu z pętli rax jest konwertowany do octoword // zeby mozna było użyć idiv sum /= n; result.min = min; result.max = max; result.average = sum; return result; } ``` Gdyby sygnatura procedury nie była wcześniej znana to powiedziałbym że jest to: `struct T* puzzle8(struct T* ret, long* a, long n)` ## Zadanie 3 :::success Autor: Andriy Bernad ::: :::info Zadanie 3. Zakładamy, że producent procesora nie dostarczył instrukcji skoku pośredniego. Rozważmy procedurę «switch_prob» z poprzedniej listy. Podaj metodę zastąpienia «jmpq *0x4006f8(,%rsi,8)» ciągiem innych instrukcji. Nie można używać kodu samo modyfikującego się(ang.self-modyfing code),ale można użyć dodatkowego rejestru. Zastanów się czy potrafisz również zastąpić instrukcję pośredniego wywołania procedury, np. «call *(%rdi,%rsi,8)», gdyby jej brakowało. ::: Tryby adresowania : **bezpośredni** - podajemy 32 bitową stałą, która określa przesunięcie względem początku pamięci (czyli adresu 0) **pośredni** przez rejestr - adres znajduje się w jednym z 32/64 bitowych rejestrów. ![](https://i.imgur.com/2BOhKie.png) Wykorzystamy rejestr `%r8` jako pomocniczy. push wrzuci ten adres na stos. ret go zdejmie i włoży do `%rip`, rip wskazuje aktualnie wykonywane polecenie. ```asm= movq 0x4006f8(,%rsi,8), %r8 push %r8 ret ``` Niepoprawne rozwiązanie p. Kacpra Puchalskiego: :::spoiler Możemy użyć rejestru %rip. To rejestr wskazujący na adres następnej wykonywanej przez nas instrukcji. Wystarczy więc podmienić skok na załadowanie adresu instrukcji do %rip jpmq $*0x4006f8(,\%rsi,8) \rightarrow$ leaq $0x4006f8(,\%rsi,8), \%rip$ ::: ## Zadanie 4 :::success Autor: Filip Pazera ::: ```diff= M: pushq %rdi testq %rdi, %rdi je .L2 leaq -1(%rdi), %rdi call M movq %rax, %rdi call F - movq (%rsp), %rdi ; nie aktualizujemy %rsp + popq %rdi subq %rax, %rdi .L2: movq %rdi, %rax ret F: testq %rdi, %rdi je .L3 + pushq %r12 movq %rdi, %r12 ; %r12 jest callee-saved leaq -1(%rdi), %rdi call F movq %rax, %rdi call M subq %rax, %r12 movq %r12, %rax + popq %r12 ret .L3: movl $1, %eax ret ``` :::spoiler Poprawiona procedura M ```diff= M: pushq %rdi testq %rdi, %rdi je .L2 leaq -1(%rdi), %rdi call M movq %rax, %rdi call F movq (%rsp), %rdi subq %rax, %rdi .L2: + addq $8, %rsp movq %rdi, %rax ret ``` ::: ## Zadanie 5 :::info Autor: Michał Doros ::: leave <=> movq %rbp %rsp popq %rbp przechodzimy do poprzedniej ramki stosu alloca alokuje n bajtów miejsca na stosie i zwalnia je automatycznie przy wyjściu z procedury, która ją wywołała ```c= ```c= 0: 55 pushq %rbp 1: 48 89 e5 movq %rsp, %rbp 4: 48 83 ec 10 subq $16, %rsp 8: 48 89 e0 movq %rsp, %rax #wsk stosu to rax b: 48 8d 0c fd 0f 00 00 00 leaq 15(,%rdi,8), %rcx #n * rozmiar longa + 15 do rcx (+15 to kwestia wyrównania/sufit) 13: 48 83 e1 f0 andq $-16, %rcx #zerujemy ostatnie 4 bity 17: 48 29 c8 subq %rcx, %rax #oblicz nowy wskaźnik stosu 1a: 48 89 c4 movq %rax, %rsp #nowy wskaźnik wrzuć do rsp 1d: 48 8d 4d f8 leaq -8(%rbp), %rcx 21: 48 89 4c f8 f8 movq %rcx, -8(%rax,%rdi,8) 26: 48 c7 45 f8 00 00 00 00 movq $0, -8(%rbp) 2e: 48 85 ff testq %rdi, %rdi 31: 7e 1d jle 29 <_aframe+0x50> 33: 31 c9 xorl %ecx, %ecx 35: 66 2e 0f 1f 84 00 00 00 00 00 nopw %cs:(%rax,%rax) 3f: 90 nop 40: 48 89 14 c8 movq %rdx, (%rax,%rcx,8) 44: 48 ff c1 incq %rcx 47: 48 39 cf cmpq %rcx, %rdi 4a: 75 f4 jne -12 <_aframe+0x40> 4c: 48 89 7d f8 movq %rdi, -8(%rbp) 50: 48 8b 04 f0 movq (%rax,%rsi,8), %rax 54: 48 8b 00 movq (%rax), %rax 57: 48 89 ec movq %rbp, %rsp #powrót do poprzedniej ramki 5a: 5d popq %rbp #wrzucenie do rbp poprzedniego adresu 5b: c3 retq ``` ## Zadanie 6 :::info Autor: Andrzej Tkaczyk ::: ```= puzzle5: subq $24, %rsp movq %rsp, %rdi call readlong leaq 8(%rsp), %rdi call readlong movq (%rsp), %rax cqto idivq 8(%rsp) xorl %eax, %eax testq %rdx, %rdx sete %al addq $24, %rsp ret ``` ```c= void readlong(long *target); ``` ```c= long puzzle5(void){ long a, b; readlong(&a); readlong(&b); return a % b == 0; } ``` rekord aktywacji: | zawartość | wielkość| |-----------|---------| | puste | 8 bajtów| | miejsce na wpisanie dla readlong | 8 bajtów| | miejsce na wpisanie dla readlong | 8 bajtów| | adres powrotu przy wołaniu readlong| 8 bajtów| ## Zadanie 7 :::success Autor: Kacper Solecki ::: ```c= typedef struct { // odstęp od reg_save_area do miejsca gdzie trzymany jest // następny argument (przekzany przez rejestr) unsigned int gp_offset; // podobny odstęp dla liczb zmiennoprzecinkowych - nie będzie nas interesować unsigned int fp_offset; // pokazuje na miejsce na stosie gdzie zachowane będą argumenty nadmiarowe (7+) void *overflow_arg_area; // pokazuje na miejsce na stosie gdzie zachowane będą argumenty z rejestrów void *reg_save_area; } va_list[1]; ``` Stos: ![](https://i.imgur.com/EAvV0Uj.jpg =400x) Funkcja przyjmuje liczbę argumentów $n$ i sumuje $n$ kolejnych argumentów. ```c= long puzzle7(long n, ...){ struct va_list va; va_start(va, n); long sum = 0; for(int i=0; i<n; i++){ sum += va_arg(va, long); } va_end(va); return sum; } ``` ## Zadanie 8 :::danger Autor: Maksymilian Debeściak :::