Lecture 4 Machine-Level Programming I: Basics
intro
Architecture(架构):指令集.
Microarchitecture:指令集的一些实现.
Machine code:机器代码(binary).
Assembly code:汇编代码(text representation of machine code).
CPU 上的一些东西:
- PC: Program Counter,记录程序跑到哪一行 (address of next
instruction,
%rip). - Register file: Registers.
- Condition Code: Condition Code.
Memory: 存储了 Code, data, stack. Memory 给 CPU 传 instruction 和 data,CPU 反过来给 Memory 传 data 和 addresses.
一个 C 程序 x.c 通过 gcc -Og -S
得到汇编程序 Asm Program x.s. Asm Program 再通过 Assembler
转化为 binary 的 Object Program x.o. 然后再结合 Static
Library (一些 printf 类的东西依赖这个) ,通过 Linker
得到最终的可执行文件 x.
registers
64 位寄存器:
rax, rbx, rcx, rdx, rdi, rsi, rsp, rbp, r[8,15].
其对应的后 32 位是:
eax, ebx, ecx, edx, edi, esi, esp, ebp, r[8,15]d
其对应的后 16 位是:
ax, bx, cx, dx, di, si, sp, bp, r[8,15]w.
其对应的最后一个 byte 是:
al, bl, cl, dl, dil, sil, spl, bpl, r[8,15]b
其中 rsp 存 stack
pointer,不能被肆意使用,其他都可以随便用,然后可能会在某些情境下被指定使用.
其中 rax
记录函数的返回值,rdi rsi rdx rcx r8 r9
分别作为传递进函数的第 \([1,6]\)
个参数.
operations
在 Linux 中,为 op Src Dest. 但是在 Intel 下是
op Dest Src. 书中全部采用前者,即 addq x y 为
\(y+=x\).
q 表示四字(quadword,64位),l
表示双字(longword,32位),w 表示字(word,16位),
b 表示字节(byte).
mov 相关注意事项:
mov指令 Src 是立即数而 Dest 是内存地址,必须指定是movq还是movl还是movw还是movb.movl会自动置零更高的 32 位,而其他不会.movz(move with zero-extend),从一个较小的 src 移到较大的 dest(eg.movzwq,movbl),用 0 扩充. 注意没有movzlq因为等价于movq.movs(move with sign-extend),同上,用符号位扩充.
rax 相关特殊指令:
cltq:针对eax,将eax符号扩充到rax变成 64 位数.cqto:针对rax,将rax符号扩充到rdx:rax变成 128 位数.imulq S:rdx:rax = rax * S(有符号)mulq S:rdx:rax = rax * S(无符号)idivq S:对于 128 位有符号整数rdx:rax,除以 \(S\),得到的商在rax,余数在rdx.执行前必须先
cqto.divq S为无符号.
D(Rb,Ri,S) = Mem[D+Rb+Ri*S]. 注意 \(S\) 只能是 1,2,4,8.
lea D(Rb,Ri,S), %rax 等于
rax = D+Rb+Ri*S,或者 rax=&....
mov D(Rb,Ri,S), %rax 等于
rax = Mem[D+Rb+Ri*S]
add,sub,imul
字面意思,加减乘.
sal / shl,sar,shr
为左右移,其中 h 为逻辑,a 为算数.
xor,and,or
字面意思,异或,与,或.
in,dec,neg,not
分别为 \(++\),\(--\),\(-\),\(\sim\).
Lecture 05: Machine-Level Programming II: Control
Conditional Codes
For any arithmetic operation (EXCLUDING leaq
instruction)
CF:Carry Flag(unsigned overflow, borrow/carry from the
MSB)
ZF:Zero Flag(if =0)
SF:Sign Flag(<0 as signed)
OF:Overflow Flag (if signed overflow, eg. \(a,b>0\) but \(a+b<0\), or \(a,b<0\) but \(a+b\ge 0\))
Explicit Settings
cmpq a b
\(b-a\), calculate w/o setting destination.
CF:unsigned comparison, \(=[b<a]\).
ZF:eq, \(=[a=b]\).
SF:signed comparison, \(=[b<a ]\).
OF:2's compliment signed overflow
testq a b
\(b\text{ and }a\), calculate w/o setting destination
ZF:\(=[b\text{&}a=0]\).
SF:\(=[b\text{&}a<0]\).use
testq a ato test equal.
Reading
setX:set the low byte of destination to:
| setX & Description | Condition |
|---|---|
sete / setne (equal) |
ZF / ~ZF |
sets / setns (negative) |
SF / ~SF |
setge / setg (\(b\ge
a\), \(b>a\), signed) |
~(SF^OF), &(~ZF) if not equal |
setle / setl (\(b\ge
a\),\(b<a\), signed) |
(SF^OF), &ZF if equal |
seta / setb (above=\(b>a\), below=\(b<a\)) |
(~CF)&(~ZF) for above, CF for
below |
use movzbl after SetX, so that the whole register
represent the result.
Conditional Branches
jX: similar to setX, with additional jmp (unconditional
jump)
cmovX: similar to setX, (if condition then move).
Sometimes the compiler calculate both side results and use cmovX for conditional branches. But it must be side-effect free, and simple calculations.
Loops
很简单
switch 跳转的时候是间接跳转(*.L3(,rax,8))