---
slideOptions:
transition: slide
tags: 'cs:app'
---
<style>
.reveal .slides {
text-align: left;
}
</style>
# CSAPP ch3
---
# History Perspective

----
- 8086(1978,29K 個電晶體):第一代是單晶片,16-bit微處理器之一
- 8087 floating-point coprocessor(1980,124K 個電晶體): 增加浮點指令集,建立x86系列的浮點模型,稱為"x87"
- Pentium(1993, 3.1M 個電晶體):(因為數字不能作為註冊商標)對指令及作些許的擴張
- PentiumPro(1995, 5.5M 個電晶體) 使用一個全新的設計(P6 microarchitecture),增加conditional move的指令
----
- Pentium III (1999, 8.2M 個電晶體) 加入SSE(Streaming SIMD Extensions,處理float運算及操作的指令),每個數據可以是1,2,4個字節,打包成128個向量,因為該晶片上的L2快取的高速,之後的版本最多有24M 個電晶體
> SSE 打包成vector

----
- Pentium 4 (2000, 42M 個電晶體) 擴展SSE至SSE2,增加新的數據處理指令(包含處理double及CPU快取控制指令)
- Core i7, Nehalem (2008, 781 M transistors) 支持hyperthreading跟多核,最多四核
- Core i7, Sandy Bridge (2011, 1.17 G transistors) 加入AVX(支援將資料打包進256-bit vector)
- Core i7, Haswell (2013, 1.4 G transistors) 將AVX擴張至AVX2,有更多的指令跟指令格式
----
> SSE2 跟 x87的差別

---
# Program Encodings
----
```c=
long mult2(long, long);
void multstore(long x, long y, long *dest) {
long t = mult2(x, y);
*dest = t;
}
```
gcc -Og -S mstore.c
```
multstore:
endbr64
pushq %rbx
movq %rdx, %rbx
call mult2@PLT
movq %rax, (%rbx)
popq %rbx
ret
```
----
- 反組譯看看
- `gcc -Og -c mstore.c`
- `objdump -d mstore.o`
```
0000000000000000 <multstore>:
0: f3 0f 1e fa endbr64
4: 53 push %rbx
5: 48 89 d3 mov %rdx,%rbx
8: e8 00 00 00 00 callq d <multstore+0xd>
d: 48 89 03 mov %rax,(%rbx)
10: 5b pop %rbx
11: c3 retq
```
----
```c=
#include <stdio.h>
void multstore(long, long, long *);
int main() {
long d;
multstore(2, 3, &d);
printf("2 * 3 --> %ld\n", d);
return 0;
}
long mult2(long a, long b) {
long s = a * b;
return s;
}
```
* 將其編譯成 excutable file
`gcc -Og -o prog main.c mstore.c`
----
* 反組譯
`objdump -d prog`
```
00000000000011d5 <multstore>:
11d5: f3 0f 1e fa endbr64
11d9: 53 push %rbx
11da: 48 89 d3 mov %rdx,%rbx
11dd: e8 e7 ff ff ff callq 11c9 <mult2>
11e2: 48 89 03 mov %rax,(%rbx)
11e5: 5b pop %rbx
11e6: c3 retq
11e7: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
11ee: 00 00
```
----
- `.` 開頭的指令我們先忽略 (linker 和 assembler 會用到)
```
.file "mstore.c"
.text
.globl multstore
.type multstore, @function
multstore:
.LFB0:
.cfi_startproc
endbr64
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
movq %rdx, %rbx
call mult2@PLT
movq %rax, (%rbx)
popq %rbx
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.
.
.
```
----
- 組語內容解析

- 需要用組合語言去做一些操做時,在用組語寫完整個function後,可以在linking階段跟C語言連接起來,或是在GCC的支援下將其嵌入C語言
---
# Data Formats
----
- `word` -> 16-bit
- `double word` -> 32-bit
- `quad word` -> 64-bit

---
# Accessing Information
----
## register配置
- 稍微記住第一排的return value跟第二排的caller saved 跟 stack poionter %rsp
- [Integer registers](https://i.imgur.com/o9mYcsV.jpg)
----
## Operand Specifiers
1. immediate: `$`,用來表示constant,ex: `$-577`、`$0x1F`
2. register: 存在register中的值。可將所有register視為一個array,暫存器a用R[a]表示
3. memory: 將記憶體視為一個超大的array,根據計算的的位址(Arrd)訪問該值時,用M[Addr] 表示
[Operand forms](https://i.imgur.com/F3w7bHf.jpg)
----
- x86-64的限制: mov 指令的兩個operand,不能同時指向memmory location
- 將一個從一個記憶體位置複製到另一個記憶體位置,需要下兩個指令
1. load source value to register
2. write the register value to destination
- five possible combinations of source and destination

----
## 將較小的source value 移動到較大的destination
- 第一個操作元代表source value的大小,第二個是distination的大小
1. [MOVZ](https://i.imgur.com/5lklxXW.jpg): 將剩下的bit都填0,ex: `movzbw`(1-byte->2-byte)
3. [MOVS](https://i.imgur.com/RfZFZWD.jpg): 複製最高有效位,ex: `movsbw`(1-byte->2-byte)
----
### 練習

----
### 答案

----
## stack

----
- Pushing and Popping Stack Data
- [stack](https://ithelp.ithome.com.tw/articles/10204444) 
- `pushq %rbp`
1. `subq $8,%rsp` Decrement stack pointer
2. `movq %rbp,(%rsp)` Store %rbp on stack
- `popq %rax`
1. `movq (%rsp),%rax` Read %rax from stack
2. `addq $8,%rsp` Increment stack pointer
---
## Arithmetic and Logical Operations
----
- 每個指令都會依照數據大小而有後綴為`b`,`w`,`l`,`q` 的指令(除了`leaq`),像是`addb`, `addw`, `addl` 跟 `addq`
- [instruction](https://i.imgur.com/YYd7K22.jpg)
----
- `leaq` 指令主要是load 位址中的值,也能執行加法和有限的乘法
```C=
long scale(long x, long y, long z) {
long t = x + 4 * y + 12 * z;
return t;
}
```
- long scale(long x, long y, long z) x in %rdi, y in %rsi, z in %rdx
```
scale:
endbr64
leaq (%rdi,%rsi,4), %rax //x + 4*y
leaq (%rdx,%rdx,2), %rdx //z + 2*z = 3*z
leaq (%rax,%rdx,4), %rax //(x+4*y) + 4*(3*z) = x + 4*y + 12*z
ret
```
----
- 表格第二組是 Unary Operations
- operand 可以是register 或 memory location(不能是 immediate)
- 表格第三組是 Binary Operations
- 第一個operand 是 source,第二個既是 source 也是 destination
- 注意: `(%rdx)-(%rax)` 的指令是 `subq %rax %rdx`,跟直覺相反,可以理解成從 %rdx 減掉 %rax
----
- 表格第四組是 Shift Operations+
- 左移的SAL跟SHL,作用是一樣的
- 右移的SAR 進行算數移位,SHL 進行邏輯移位
- 因為只有右移有區分有號無號數,使得補數成為一個比較好執行有號數運算的方式
----
- 位移量可以是一個 immediate 或存在 %cl 中,也就是說位移量最大可以到 $2^8-1=255$
- 對w-bit的值移位,其位移量只會由%cl的低m位決定($2^w=m$)
- Ex: %cl的值是0xFF時, salb>>7 、salw>>15
----
```C=
long shift_left4_rightn(long x, long n) {
x <<= 4;
x >>= n;
return x;
}
```
x in %rdi, n in %esi
```
shift_left4_rightn:
endbr64
movq %rdi, %rax
salq $4, %rax
movl %esi, %ecx
sarq %cl, %rax
ret
```
----
- 前面第二章提到的,兩個64位元的運算需要用到128位元來表示,以上是x86-64支援產生兩個64位元的全128位元乘除指令
- oct word: 128-bit

----
- 範例
```C=
#include <inttypes.h>
typedef unsigned __int128 uint128_t;
void store_uprod(uint128_t *dest, uint64_t x, uint64_t y) {
*dest = x * (uint128_t) y;
}
```
----
```
store_uprod:
endbr64
movq %rsi, %rax //Copy x to multiplicand
mulq %rdx //Multiply by y
movq %rax, (%rdi) //Store lower 8 bytes at dest
movq %rdx, 8(%rdi) //Store upper 8 bytes at dest+8
ret
```
----
```C=
void remdiv(long x, long y,long *qp, long *rp) {
long q = x/y;
long r = x%y;
*qp = q;
*rp = r;
}
```
```
remdiv:
endbr64
movq %rdi, %rax //Copy qp
movq %rdx, %r8 //Move x to lower 8 bytes of dividend
cqto //Sign-extend to upper 8 bytes of dividend
idivq %rsi //Divide by y
movq %rax, (%r8) //Store quotient at qp
movq %rdx, (%rcx)//Store remainder at rp
ret
```
---
# Control
----
## Condition Codes
1. CF: Carry flag. 檢查最近一次運算是否使得最高位產生進位
2. ZF: Zero flag. 檢查最近一次運算結果是否為零
3. SF: Sign flag. 檢查最近一次運算的結果是否為負數
4. OF: Overflow flag. 檢查最近一次運算是否使得一個二補數overflow
----
- 用C表示 `t = a+b`
|指令|C expressions|描述|
| --- | --- | --- |
|CF| (unsigned) t < (unsigned) a |Unsigned overflow|
|ZF| (t == 0) |Zero|
|SF| (t < 0) |Negative|
|OF| (a < 0 == b < 0) && (t < 0 != a < 0) |Signed overflow|
----
- 除了`leaq`進行address的運算,不會改變任何condition code 之外,以下所列的指令都會設置condition code
- [Arithmetic and Logical Operations](https://i.imgur.com/IoV193l.jpg)
- 
----
- CMP 會由兩值的差設定condition code,行為跟SUB一樣,不過不會改變destination的值。要注意ATT 格式,所以兩值的順序會相反
- TEST 會由兩值的和設定condition code,行為跟AND一樣,不過不會改變destination的值,一個典型的用法是兩個操作值都一樣,
`testq %rax,%rax` 檢測 %rax 是正數、負數、零
----
## Accessing the Condition Codes
- SET指令的後最是條件而非數值的大小,ex:`setb`、`setl`分別表示`set less`、`set below`
- SET指令

----
```C=
int comp(int a, int b) {
return a == b;
}
```
```
comp:
endbr64
cmpl %esi, %edi
sete %al
movzbl %al, %eax //Clear rest of %eax (and rest of %rax)
ret
```
----
## Jump Instructions
- jump 指令可使執行切換到程式中另一個位置
- jmp 是無條件跳轉,可以直接跳轉,或是間接跳轉,而條件跳轉只能直接跳轉
- jmp 間接跳轉的兩種方式
1. `jmp *%rax` : 取用register %rax中的值作為jump的目標
2. `jmp *(%rax)` : 先從register %rax讀到address,再從記憶體讀jump目標
----
- jump指令

----
- jump 指令編寫時,通常採用PC relative表示跳轉的目標
- PC relative: 將目標指令與跳轉目標後一個指令的address之間的差作為指令的參數
- 注意: program counter 的值是jump 指令後面那個值得address,而非指令本身
----
> 範例
> 
> 
> 往前的話就溢位
----
## Conditional Move Instructions

- 現在就能實現if else條件句、while迴圈、swtich case...囉~
----
## if-else(Conditional Control)
```C=
long lt_cnt = 0;
long ge_cnt = 0;
long absdiff_se(long x, long y)
{
long result;
if (x < y) {
lt_cnt++;
result = y - x;
}
else {
ge_cnt++;
result = x - y;
}
return result;
}
```
----
- goto
```C=
long lt_cnt = 0;
long ge_cnt = 0;
long gotodiff_se(long x, long y){
long result;
if (x >= y)
goto x_ge_y;
lt_cnt++;
result = y - x;
return result;
x_ge_y:
ge_cnt++;
result = x - y;
return result;
}
```
----
```
absdiff_se:
endbr64
movq %rsi, %rax
cmpq %rsi, %rdi
jge .L2
addq $1, lt_cnt(%rip)
subq %rdi, %rax
ret
.L2:
addq $1, ge_cnt(%rip)
subq %rsi, %rdi
movq %rdi, %rax
ret
```
----
- 自己反組譯看看
- gcc -c con.c
- objdump -d con.o
- address 去哪了?
```
0000000000000000 <absdiff_se>:
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 48 89 7d e8 mov %rdi,-0x18(%rbp)
c: 48 89 75 e0 mov %rsi,-0x20(%rbp)
10: 48 8b 45 e8 mov -0x18(%rbp),%rax
14: 48 3b 45 e0 cmp -0x20(%rbp),%rax
18: 7d 20 jge 3a <absdiff_se+0x3a>
1a: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # 21 <absdiff_se+0x21>
21: 48 83 c0 01 add $0x1,%rax
25: 48 89 05 00 00 00 00 mov %rax,0x0(%rip) # 2c <absdiff_se+0x2c>
2c: 48 8b 45 e0 mov -0x20(%rbp),%rax
30: 48 2b 45 e8 sub -0x18(%rbp),%rax
34: 48 89 45 f8 mov %rax,-0x8(%rbp)
38: eb 1e jmp 58 <absdiff_se+0x58>
3a: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # 41 <absdiff_se+0x41>
41: 48 83 c0 01 add $0x1,%rax
45: 48 89 05 00 00 00 00 mov %rax,0x0(%rip) # 4c <absdiff_se+0x4c>
4c: 48 8b 45 e8 mov -0x18(%rbp),%rax
50: 48 2b 45 e0 sub -0x20(%rbp),%rax
54: 48 89 45 f8 mov %rax,-0x8(%rbp)
58: 48 8b 45 f8 mov -0x8(%rbp),%rax
5c: 5d pop %rbp
5d: c3 retq
```
----
- 那是linux的保護機制
- gcc -c con.c -no-pie
- 就會有address了~
----
## if-else(Conditional Moves)
- Original C code
```C=
long absdiff(long x, long y) {
long result;
if (x < y)
result = y - x;
else
result = x - y;
return result;
}
```
----
```
absdiff:
endbr64
movq %rsi, %rax
cmpq %rsi, %rdi
jge .L2
subq %rdi, %rax
ret
.L2:
subq %rsi, %rdi
movq %rdi, %rax
ret
```
----
- using conditional assignment
- `gcc -O1 -S conditional.c`
```C=
long absdiff(long x, long y) {
long result;
if (x < y)
result = y - x;
else
result = x - y;
return result;
}
```
----
```
absdiff:
endbr64
movq %rsi, %rdx
subq %rdi, %rdx
movq %rdi, %rax
subq %rsi, %rax
cmpq %rsi, %rdi
cmovl %rdx, %rax
ret
```
----
## loop
- do-while loop
```C=
long fact_do(long n) {
long result = 1;
do {
result *= n;
n = n - 1;
}
while (n > 1);
return result;
}
```
----
```
fact_do:
endbr64
movl $1, %eax
.L2:
imulq %rdi, %rax
subq $1, %rdi
cmpq $1, %rdi
jg .L2
ret
```
----
```C=
long fact_while(long n) {
long result = 1;
while (n > 1) {
result *= n;
n = n - 1;
}
return result;
}
```
----
```
act_while:
endbr64
movl $1, %eax
.L2:
cmpq $1, %rdi
jle .L4
imulq %rdi, %rax
subq $1, %rdi
jmp .L2
.L4:
ret
```
----
- for loop
```C=
long fact_for_while(long n) {
long i = 2;
long result = 1;
while (i <= n) {
result *= i;
i++;
}
return result;
}
```
----
```
fact_for_while:
.LFB0:
.cfi_startproc
endbr64
movl $1, %edx
movl $2, %eax
.L2:
cmpq %rdi, %rax
jg .L4
imulq %rax, %rdx
addq $1, %rax
jmp .L2
.L4:
movq %rdx, %rax
ret
```
----
## switch
```C=
void switch_eg(long x, long n,
long *dest) {
long val = x;
switch (n) {
case 100:
val *= 13;
break;
case 102:
val += 10;
/* Fall through */
case 103:
val += 11;
break;
case 104:
case 106:
val *= val;
break;
default:
val = 0;
}
*dest = val;
}
```
----
```
switch_eg:
endbr64
subq $100, %rsi
cmpq $6, %rsi
ja .L8
leaq .L4(%rip), %rcx
movslq (%rcx,%rsi,4), %rax
addq %rcx, %rax
notrack jmp *%rax
.section .rodata
.align 4
.align 4
.L4:
.long .L7-.L4
.long .L8-.L4
.long .L6-.L4
.long .L5-.L4
.long .L3-.L4
.long .L8-.L4
.long .L3-.L4
.L7:
leaq (%rdi,%rdi,2), %rax
leaq (%rdi,%rax,4), %rdi
jmp .L2
.L6:
addq $10, %rdi
.L5:
addq $11, %rdi
.L2:
movq %rdi, (%rdx)
ret
.L3:
imulq %rdi, %rdi
jmp .L2
.L8:
movl $0, %edi
jmp .L2
```
- .rodata : read_only data
----
- goto 表示
```
void switch_eg_impl(long x, long n,
long *dest) {
/* Table of code pointers */
static void *jt[7] = {
&&loc_A, &&loc_def, &&loc_B,
&&loc_C, &&loc_D, &&loc_def,
&&loc_D
};
unsigned long index = n - 100;
long val;
if (index > 6)
goto loc_def;
/* Multiway branch */
goto *jt[index];
loc_A: /* Case 100 */
val = x * 13;
goto done;
loc_B: /* Case 102 */
x = x + 10;
/* Fall through */
loc_C: /* Case 103 */
val = x + 11;
goto done;
loc_D: /* Cases 104, 106 */
val = x * x;
goto done;
loc_def: /* Default case */
val = 0;
done:
*dest = val;
}
```
----
- switch table
```
.L4:
.long .L7-.L4
.long .L8-.L4
.long .L6-.L4
.long .L5-.L4
.long .L3-.L4
.long .L8-.L4
.long .L3-.L4
```
---
# Procedures
---
* Passing control
* Passing data
* Allocating and deallocating memory
---
> 用3.4節提到的pushq和popq指令儲存或取出數據

---
* 將控制從 function P 轉移到 function Q 只需要將 program counter(PC) 設為 Q 的起始位址,指令`call Q`調用過程 Q 紀錄回到 P 之後的執行位址。
* `call Q`會把 adddressA push 進 stack,並將 PC 設為 Q 的起始位址,addressA 被稱為 return address,位址在 call 指令的後面。
* `ret` pop 出 addressA 並把 PC 設為 addressA
> call和ret的一般形式

---
> 以3.2的multstore和main的情況來看

---
* 調用過程的前6個 function argument 會依下圖的順序放在暫存器

* 剩下的會堆在 stack 裡,會從最後一個開始堆到第7個
---


---
## Local storage
- on the stack


---
- in register


---
## Recursive


---
# Array Allocation and Access
---
## Basic Principles
* 對於型別 T 和整數 N,`T A[N]`的起始位置為x~A~,型別 T 的大小為 L,A[i]的位址為x~A~+L · i。

* 假設 E 是一個陣列,L 是其型別大小,當 E 的位址在%rdx、i 在%rcx,要將 E[i] 的位址存在%eax,指令為`movl (%rdx,%rcx,L),%eax`。
---
## Pointer Arithmetic
* data存在%eax、pointer存在%rax

---
## Nest Arrays
* `T D[R][C]`的記憶體位置為 &D[i][j] = xD~ + L(C . i + j),L 是 T 型別的大小。

---
## Fixed-Size Arrays
```C=
#define N 16
.typedef int fix_matrix[N][N];
```



---
## Variable-Size Arrays


---
# Heterogeneous Data Structures
---
## Structures
```C=
struct rec {
int i;
int j;
int a[2];
int *p;
};
```

---
`r-> p = &r->a[r->i + r->j];`

---
## Unions
```C=
struct S3 {
char c;
int i[2];
double v;
};
union U3 {
char c;
int i[2];
double v;
};
```

* union的pointer都會指向結構的起始位址
---
## Data Alignment
* `.align 8`
```C=
struct S1 {
int i;
char c;
int j;
}
```
* 假設分配最小的 9byte

* 用`align 8` 的樣子

---
* 尾端有時候需要補滿
```C=
struct S2 {
int i;
int j;
char c;
};
```
`struct S2 d[4]`

---
## Combining Control and Data in Machine-Level Programs
----
### pointer
* pointer: value is address of an object of designated type
* object: a contiguous sequence of bytes storage in memory with address
----
* `int a`
* object of type int
----
* `int *b`
* pointer to an object of type int
----
* `int **c`
* pointer to an object that itself is a pointer to an object of type int
----
* `int ***d`
* pointer to an object that itself is a pointer to an object that itself is a pointer to an object of type int
----

----
* `int *p = NULL`
* pointer to nothing
----
* `int a; &a;`
* address of object a
----
* `int (*func) (int)`
* function pointer with a int argument
* func 是一坨 machine code 存在 memory
----
### gdb
----

----

----
### Out-of-Bounds Memory References and Buffer Overflow
* local variable 超出範圍會損毀 stack frame 甚至造成攻擊
----
* vulnerable function:
```c
char *gets(char *s)
{
int c;
char *dest = s;
while ((c = getchar()) != ’\n’ && c != EOF)
*dest++ = c;
if (c == EOF && dest == s)
/* No characters read */
return NULL;
*dest++ = ’\0’; /* Terminate string */
return s;
}
```
----
* source:
```c
void echo()
{
char buf[8]; /* Way too small! */
gets(buf);
puts(buf);
}
```
----
* asm:
```
void echo()
1 echo:
2 subq $24, %rsp Allocate 24 bytes on stack
3 movq %rsp, %rdi Compute buf as %rsp
4 call gets Call gets
5 movq %rsp, %rdi Compute buf as %rsp
6 call puts Call puts
7 addq $24, %rsp Deallocate stack space
8 ret Return
```
* stack 結構:

----
* 更改 ret addr 可以執行 memory 上任意 addr 的 machine code
* 可以在 stack 內塞 machine code 然後 ret 到該位置達到任意執行的效果
* 程式對網路開放代表所有人可以在該電腦上執行任意程式
----
### 防禦機制
----
### Stack Randomization
* ASLR
* stack 的 address 是隨機的
* 攻擊者更難找到可以使用的 memory
* 可以用 `nop sled` 的技巧配上 brute force 來猜 address
----
* source:
```c
int main() {
long local;
printf("local at %p\n", &local);
return 0;
}
```
----
### Stack Corruption Detection
* canary
* 在 ret addr 上多加一個 8 bytes 的 canary,如果被更改就執行 exception
----
* 示意圖:

----
* asm:

----
### Limiting Executable Code Regions
* NX
* 可以設定 section RWX (read/write/exection) 權限
----
### Variable-Size Stack Frames
* alloca
* compiler 幫你搞定
----
* source:
```c
long vframe(long n, long idx, long *q) {
long i;
long *p[n];
p[0] = &i;
for (i = 1; i < n; i++)
p[i] = q;
return *p[idx];
}
```
----
* asm:

----
* 示意圖

---
## Floating-Point Code
----
* 很多版本的更迭 (history 有提到)
* 此書使用 AVX2
----
### register
* ymm: 32 bytes
* xmm: 16 bytes
----
* register (上)

----
* register (下)

----
### move instruction



----
* src2 是直接複製去除 source1 大小前面的 bits 到 dest
----
* source:
```c
float float_mov(float v1, float *src, float *dst) {
float v2 = *src;
*dst = v1;
return v2;
}
```
* asm:

----
* 正常猜測 single to double 是
* `vcvtss2sd %xmm0, %xmm0, %xmm0`
* 但 gcc 自己搞了以下 code


----
* source:
```c
double fcvt(int i, float *fp, double *dp, long *lp)
{
float f = *fp; double d = *dp; long l = *lp;
*lp = (long) d;
*fp = (float) i;
*dp = (double) l;
return (double) f;
}
```
----
* 書上的 asm

----
* 然後我在自己電腦上邊的 asm 長這樣
```
0x0000000000001169 <+0>: endbr64
0x000000000000116d <+4>: vxorps %xmm1,%xmm1,%xmm1
0x0000000000001171 <+8>: vmovss (%rsi),%xmm0
0x0000000000001175 <+12>: mov (%rcx),%rax
0x0000000000001178 <+15>: vcvttsd2si (%rdx),%r8
0x000000000000117d <+20>: mov %r8,(%rcx)
0x0000000000001180 <+23>: vcvtsi2ss %edi,%xmm1,%xmm2
0x0000000000001184 <+27>: vmovss %xmm2,(%rsi)
0x0000000000001188 <+31>: vcvtsi2sd %rax,%xmm1,%xmm1
0x000000000000118d <+36>: vmovsd %xmm1,(%rdx)
0x0000000000001191 <+40>: vcvtss2sd %xmm0,%xmm0,%xmm0
0x0000000000001195 <+44>: retq
```
----
* XX沒有那 4 ㄍ指令啊= =
* 取而代之真的是 vcvtss2sd 啊= =
* 顯然是時代的眼淚QQ
* 這 4 ㄍ指令內容還很奇葩,害我看了很久才看懂,有興趣自己翻書
----
### procedure
* argument: %xmm0–%xmm7
* 剩下的放 stack
* return: %xmm0
* 跟非 floating point 的 register 不衝突
----
* source1:
```c
double f1(int x, double y, long z);
```
x in %edi, y in %xmm0, and z in %rsi
* source2:
```c
double f2(double y, int x, long z);
```
x in %edi, y in %xmm0, and z in %rsi
* source3:
```c
double f1(float x, double *y, long *z);
```
x in %xmm0, y in %rdi, and z in %rsi
----
### arthmetic instruction

----
* source:
```c
double funct(double a, float x, double b, int i)
{
return a*x - b/i;
}
```
----
* 書上的 asm
```
1 funct:
The following two instructions convert x to double
2 vunpcklps %xmm1, %xmm1, %xmm1
3 vcvtps2pd %xmm1, %xmm1
4 vmulsd %xmm0, %xmm1, %xmm0 Multiply a by x
5 vcvtsi2sd %edi, %xmm1, %xmm1 Convert i to double
6 vdivsd %xmm1, %xmm2, %xmm2 Compute b/i
7 vsubsd %xmm2, %xmm0, %xmm0 Subtract from a*x
8 ret
```
----
* 我電腦上編的 asm
```
0000000000000000 <funct>:
0: f3 0f 1e fa endbr64
4: c5 f2 5a c9 vcvtss2sd %xmm1,%xmm1,%xmm1
8: c5 f3 59 c8 vmulsd %xmm0,%xmm1,%xmm1
c: c5 f8 57 c0 vxorps %xmm0,%xmm0,%xmm0
10: c5 fb 2a c7 vcvtsi2sd %edi,%xmm0,%xmm0
14: c5 eb 5e c0 vdivsd %xmm0,%xmm2,%xmm0
18: c5 f3 5c c0 vsubsd %xmm0,%xmm1,%xmm0
1c: c3 retq
```
----
### Floating-Point Constants
* 直接塞 long 在 section 大法
----
* source:
```c
double cel2fahr(double temp)
{
return 1.8 * temp + 32.0;
}
```
* asm:

----
### Bitwise

----
### compare


----
* source:
```c
typedef enum {NEG, ZERO, POS, OTHER} range_t;
range_t find_range(float x)
{
int result;
if (x < 0)
result = NEG;
else if (x == 0)
result = ZERO;
else if (x > 0)
result = POS;
else
result = OTHER;
return result;
}
```
----
* asm:
