# 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
:::

```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
:::

```=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.

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:

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
:::