ICS-汇编1

2025-09-23

ICS

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. movzwqmovbl),用 0 扩充. 注意没有 movzlq 因为等价于 movq.
  • movs(move with sign-extend),同上,用符号位扩充.

rax 相关特殊指令:

  • cltq:针对 eax,将 eax 符号扩充到 rax 变成 64 位数.

    cqto:针对 rax,将 rax 符号扩充到 rdx:rax 变成 128 位数.

  • imulq Srdx:rax = rax * S(有符号)

    mulq Srdx: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]

addsubimul 字面意思,加减乘.

sal / shlsarshr 为左右移,其中 h 为逻辑,a 为算数.

xorandor 字面意思,异或,与,或.

indecnegnot 分别为 \(++\)\(--\)\(-\)\(\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 a to 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)