unix> gcc -O1 -o p p1.c p2.c
-O1 最佳化1
流程
這樣可以執行了嗎?
到這一步時候所有指令都已經被轉換成為機械碼,可是 global value 的位址還未被決定
ISA(Instructure set architecture) defines the format and behavior of processor.
Memory addresses used by machine-level program is "virtual address" -> Chapter 9
在 Mechine-Level 程式裡有許多需要被額外注意的暫存器
Program Memory includes
gcc -O1 -S code.c
cat sum.s
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 10, 15 sdk_version 10, 15, 6
.globl _sum ## -- Begin function sum
.p2align 4, 0x90
_sum: ## @sum
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
movl %edi, %eax
addl %esi, %eax
addl %eax, _accum(%rip)
popq %rbp
retq
.cfi_endproc
## -- End function
.globl _accum ## @accum
.zerofill __DATA,__common,_accum,4,2
.subsections_via_symbols
.file "simple.c"
開頭為 . 的均為予 linker 用途
ATT( AT&T) vs Intel format
-看架構
前 6 個視作 general-purpose register 但有些指令有特定的用途
%esp %ebp -> program stack
logical vs arithmetic
condition behavior : loop switch and conditional execution -> jump instruction
CPU maintain a set of single-bit condition code
CF: Carry Flag - 最近的指令所產生的值得最大位 bit
ZF: Zero Flag - 最近的指令所產生的值 = 0
SF: Sign Flag - 最近的指令所產生的值 = 負數
OF: Overflow Flag - 最近的指令所產生的值造成2補數的 Overflow
CMP
TEST
SET
indirect jmp :
jmp *(%eax)
Chapter 7 會講述linking 時候 jmp 的目標細節
most common: PC relative -> offset (1 2 4 bytes)
absolute address (4 bytes)
while vs do-while
for(init;test-expr;update-expr)
綜觀上述,傳統上進行分支操作時都會以 control 作為分支,也就是說跳遇到指定的地點進行指令。
有個比較高效率的方式為透過 data ,也就是說兩者均執行但只取用整確的分支。其實作在新進的IA32架構上。
曾經的 conditional move instruction 因為 gcc 不轉譯 (過往相容問題) 其程式碼故很少用到,其用途為 nop 或者 將 controll flag mov 至 目標 register 上。
可以手動讓 gcc 使用 conditional move instruction
gcc -march=i686
IA232 不支援 單byte的condition mov instruction
i | address |
---|---|
0x20 | 0xff858545 |
gcc 的一個op -> && ,用以放置code location pointer。
jmp *.L7(,%eax,4) goto *jmptable[i]
大部分硬體只做到 control from one part of a program to another,參數傳遞以及local value 透過 program stack 實現。
%ebp -> 主要用這個
%esp -> 會隨著程式進行動態調整
詳讀參考-> https://xz.aliyun.com/t/2554
caller / callee save register
callee save: %ebx %esi %edi
這代表當 P -> Q 時候, Q必須先把這些存起來放置,並且在 ret 回去前要將這些放回去
放置會透過先 %esp 的方式進行
遞迴 > push callee save register
-> malloc/ calloc
int n;
array[n][n]
endian 議題
-O1 vs -O2
security monoculture -> address stack layout randomization(ASLR) ->nop sled buffer overflow
Stack Corruption Dection ->canary
gcc -fno-stack-protector
gcc-stack protector -> every extra space will be referred as guard value
limiting which portions of memory can hold executable code
C中插入組語:
IA32 -> IA64
VLIW instruction packs into bundles -> higher degree of parallel execution
簡述:
與IA32相似
Procedure:
由於擴充許多暫存器,故不需要遵守先前IA32 caller callee 所制定 procedure 流程
x68 Procedure:
Argument passing
Stack frames
對於 leaf procedure 而言其實不太需要 push 東西進 stack 中,大部分僅僅需要存放進 stack 的東西為 return address
換句話說,其實需要放進 stack 中的時機只有下述情況
對於 x86 系統中,Procedure 對於 stack 操作不像是 IA32 那麼頻繁。 x86 的 stack frame 經常為固定大小,此會再 procedure 發生時決定(也就是 %rbp),也就是說其實用不到指向stack頂端的 pointer。
當caller 呼叫 callee 時候,會將 return address 先 push 進去 stack 當中。當由 callee 回到 caller 時候,會將 stack 的值 pop 出來。所以對於 caller 而言,對於 offset of stack pointer 並不會影響。
Register Saving Convention
x86 callee save register
%rbx %rbp %r12 - %r15
x86-64 ABI specties that programs can use the 128 bytes beyond the current stack pointer. The ABI refers to this area as the red zone.
x86 follows a more stringent set of alignment requirements.
just-in-time compilation -> byte code -> 可以適應在多種平台上
第3章如果老師所說確實是瓶頸,花了好多時間研讀以及做題目,對於之前不了解於 x86-64 以及 i386 架構上的 coroutine 差別也能有清楚認知,非常值得熟讀此章。不過這處講述的還挺偏表層的,細部還有許多尚須探討。