信息的表示与处理
信息储存
大小端序
x86 x64采取小端序 ,低字节存放低位。
常见的ARM采取大端序,低字节存放高位。
整数表示
无符号
有符号(补码)
有无符号转换
int x;
IEEE浮点数
float=1Sign+9Exp+23Frac
double=1Sign+11Exp+52Frac
s为符号,M称为尾数,E称为阶码。
1.规格化的值
当Exp即非全1,也非全0时,浮点数表示一个规格化的值。
此时,
,其中
Frac被解释为小数,那么
2.非规格化的值
当Exp为全0时,浮点数表示非规格化的值,此时
3.特殊值
当Exp为全1时,浮点数表示一些特殊值。
如果Frac全为0,表示无穷,即
其它时候,float表示的值被称为NaN(Not a Number)
信息处理
移位运算
左移
总在右侧补0。
算术右移
根据需求补0或补1,实现
的期待算术功能。
逻辑右移
总在左侧补0,实现逻辑功能。
位扩展
零扩展
对于无符号数,我们只需要简单地在左侧补零即可。
符号扩展
根据符号左侧补0或补1,这样可以保证有符号数的值不变。
截断数字
无符号数截断
无符号数直接截断。
有符号数截断
有符号数先转化为无符号数,截断后再转换回来。
整数加法
无符号加法
无符号加法逆元
补码加法
补码加法逆元
整数乘法
无符号乘法
补码乘法
补码乘法和无符号乘法在位级是等价的。
浮点数的舍入
IEEE浮点数采取向偶数舍入的方式,自动向最接近的值舍入,即
待社区的部分低于新的最低位的一半时舍去,大于时则进位;
如果恰好等于最低位的一半,我们应该让新的最低位为0(前最低为1则进位,否则舍去)
程序的机器级表示
数据格式
类型 | 汇编代码后缀 | 大小(Bytes) |
---|---|---|
Byte | b | 1 |
Word | w | 2 |
Double Words | l | 4 |
Quad Words | q | 8 |
Single | s | 4 |
Double | l | 8 |
访问信息
寄存器
64位名称 | 32位名称 | 16位名称 | 8位名称 | 特殊作用/被谁保存 |
---|---|---|---|---|
rax | eax | ax | al | 返回值 |
rbx | ebx | bx | bl | 被调用者保存 |
rcx | ecx | cx | cl | 参数4 |
rdx | edx | dx | dl | 参数3 |
rsi | esi | si | sil | 参数2 |
rdi | edi | di | dil | 参数1 |
rbp | ebp | bp | bpl | 被调用者保存 |
rsp | esp | sp | spl | 栈指针 |
r8 | r8d | r8w | r8b | 参数5 |
r9 | r9d | r9w | r9b | 参数6 |
r10 | r10d | r10w | r10b | 调用者保存 |
r11 | r11d | r11w | r11b | 调用者保存 |
r12 | r12d | r12w | r12b | 被调用者保存 |
r13 | r13d | r13w | r13b | 被调用者保存 |
r14 | r14d | r14w | r14b | 被调用者保存 |
r15 | r15d | r15w | r15b | 被调用者保存 |
操作数操作符(AT&T)
格式 | 操作数值 | 名称 |
---|---|---|
$Imm | Imm | 立即数 |
r | R[r] | 寄存器 |
Imm | M[Imm] | 直接寻址 |
(r) | M[R[r]] | 间接寻址 |
Imm(r) | M[R[r]+Imm] | 间接寻址 |
M[R+R] | 变址寻址 | |
M[R+R+Imm] | 变址寻址 | |
M[] | 比例变址寻址 | |
M[] | 比例变址寻址 | |
M[] | 比例变址寻址 | |
M[] | 比例变址寻址 |
控制
条件码
条件码寄存器
CPU还维持着一组单个位的条件码构成的寄存器。
条件码 | 名称 | 意义 | 执行t=a+b时的C表述 |
---|---|---|---|
CF | 进位标志 | 最高位进位 | (unsigned)t<(unsigned)a |
ZF | 零标志 | 结果为0 | t==0 |
SF | 符号标志 | 结果为负数 | t<0 |
OF | 溢出标志 | 结果发生补码溢出 | (a<0==b<0)&&(t<0!=a<0) |
条件指令后缀
后缀 | 同义后缀 | 对应条件码 | 对于表达式a<b的条件 |
---|---|---|---|
e | z | ZF | 相等 |
ne | nz | ~ZF | 不等 |
s | SF | 负数 | |
ns | ZF | 非负数 | |
g | nle | ~(SF^OF)& ~ZF | 有符号> |
ge | nl | ~(SF^OF) | 有符号>= |
l | nge | SF^OF | 有符号< |
le | ng | (SF^OF)|ZF | 有符号<= |
a | nbe | ~CF& ~ZF | 无符号> |
ae | nb | ~CF | 无符号>= |
b | nae | CF | 无符号< |
be | na | CF|ZF | 无符号<= |
抽象结构的实现
条件分支结构
if和三目运算符
使用条件传送(cmov__)和条件跳转(j__)可实现三目运算符(A?B:C)和条件分支(if...else if...else...)
switch
当开关情况较多,且分布密集时,编译器将使用跳转表来翻译switch。
跳转表是一个由跳转地址构成的数组,那么switch可以根据被选择的值,确定到这个数组的某一位,来完成跳转。
对于default等情况,只需要单独判断即可。
循环结构
do-while
对于
do{
body-statement
}while(test-expr)
总能转化为
loop:
body-statement
if (test-expr) goto loop;
进而转化为汇编
.Loop
body-statement-asm
calculate-test-expr-asm
j__ .Loop
while
对于
while(test-expr){
body-statement
}
总能转化为
goto test;
loop:
body-statement
test:
if (test-expr) goto loop;
进而转化为汇编
jmp .Test
.Loop
body-statement-asm
.Test
calculate-test-expr-asm
j__ .Loop
这种翻译方式被称为jump-to-middle。
还有一种翻译方式被称为guard-do方式,它将有更高的执行效率。
源代码总能转化为
if (!(test-expr)) goto done;
loop:
body-statement
if (test-expr) goto loop;
done:
进而转化为汇编
calculate-test-expr-asm
j__ .Done
.Loop
body-statement-asm
calculate-test-expr-asm
j__ .Loop
.Done
for
对于
for(init-expr;test-expr;update-expr){
body-statement
}
总能转化为
init-expr
while(test-expr){
body-statement
update-expr
}
也就可以使用while的两种翻译方式。
栈帧结构
上一个过程的栈帧 | 输入参数(7+) | |
---|---|---|
.. | ...... | |
.. | 返回地址 | |
当前栈帧 | 上一个过程的帧指针 | rbp |
.. | 本过程的变量 | |
.. | ...... | |
.. | 要传递的参数(7+) | |
.. | ...... | |
.. | 返回地址 | rsp |
汇编指令
数据传送指令
mov S,D; 把S的值复制到D
;movq, movl, movw, movb,除了movl外,只更新指定的字节,movl还会将高4字节置0
movabsq S,D
;对于movq,其源只能为32位补码数字,而movabsq可以使用64位立即数,但是只能以寄存器作为目标。
movz S,D;把S零扩展后的值复制到D
;movzbw,movzbl,movzbq,movzwl,movzwq,movl相当于movzlq
movs S,D;把S符号扩展后的值复制到D
;movsvw,movsbl,movsbq,movswl,movswq,movslq
cltq ;把eax符号扩展为rax
cmov__ S,D;'__'表示条件后缀,条件传送S到D
压入/弹出栈指令
x86-64的栈向下增长,栈顶数据位于低地址。
pushq S;栈指针-8,然后S入栈
popq D;弹出栈顶到D,然后栈指针+8
算术/逻辑指令
取地址指令
lea S,D;取S的地址到D
对于这样的S,实际上是计算算术运算并赋值到D,编译器经常使用这样的奇怪用法。lea的目的操作数必须是寄存器。
单操作数指令
inc D;D++
dec D;D--
neg D;D=-D
not D;D=~D
算术指令
add S,D;D+=S
sub S,D;D-=S
IMUL S,D;D*=S
逻辑指令
xor S,D;D^=S
and S,D;D&=S
or S,D;D|=S
SAL k,D;D<<=k
SHL k,D;D<<=k
SAR k,D;D=((signed)D)>>k
SHR k,D;D=((unsigned)D)>>k
特殊算术指令
以下指令对128位数提供有限支持。
imulq S;有符号乘法
mulq S;无符号乘法
clto ;符号扩展为八字
idivq S;有符号除法
divq S;无符号除法
imulq/mulq将S和rax的两个64位整数相乘,结果储存到rdx:rax组成的128位寄存器中。
clto则将rax中的值符号扩展为rdx:rax的128位值
idivq/divq将rdx:rax的128位值除以S,然后商保存到rax,余数保存到rdx
条件码访问指令
set D
cmp B,A
test A,B
set+<条件后缀>将对应的条件值赋值给D。
cmp指令根据对A和B的比较情况设置条件码。
test指令根据A&B的情况设置条件码
跳转指令
jmp D
jmp *D
j__ D
j__ *D
跳转指令分为直接跳转和间接跳转,直接跳转是跳转到某个程序指定的位置,间接跳转则是跳转到D指向的位置。
jmp指令为无条件跳转,而j+<条件后缀>的指令则为条件跳转。
利用条件跳转可以实现程序的条件分支(if...else if...else...)
控制转移指令
call D
call *D
ret
call指令调用过程D,或者D指向的过程(*D)。执行该指令,会将返回地址入栈,然后改变程序计数器的值。
ret指令表示从当前过程返回到调用者,即从栈中弹出地址,然后设置PC为该地址。
处理器体系结构
Y86-64
架构状态
寄存器
除了r15以外的所有x86-64寄存器。
r15用于指令不需要寄存器时的占位。
程序状态
条件码CC: ZF,SF,OF
程序状态: Stat
指令集与编码
指令 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
halt | 0 | 0 | ||||||||
nop | 1 | 0 | ||||||||
cmovxx rA,rB | 2 | fn | rA | rB | ||||||
irmovq V,rB | 3 | 0 | F | rB | V | .. | .. | .. | .. | .. |
rmmovq rA,D(rB) | 4 | 0 | rA | rB | D | .. | .. | .. | .. | .. |
mrmovq D(rB),rA | 5 | 0 | rA | rB | D | .. | .. | .. | .. | .. |
OPq rA,rB | 6 | fn | rA | rB | ||||||
jXX Dest | 7 | fn | Dest | .. | .. | .. | .. | .. | .. | .. |
call Dest | 8 | 0 | Dest | .. | .. | .. | .. | .. | .. | .. |
ret | 9 | 0 | ||||||||
pushq rA | A | 0 | rA | F | ||||||
popq rA | B | 0 | rA | F |
特点
1-10字节的信息,从内存读取
根据第一字节可判断指令长度
比x86-64的指令类型少
比x86-64的编码简单
每次存取更改程序状态的一些部分
fn编码
cmovXX
指令 | fn |
---|---|
rrmovq | 0 |
cmovle | 1 |
cmovl | 2 |
cmove | 3 |
cmovne | 4 |
cmovge | 5 |
cmovg | 6 |
OPq
指令 | |
---|---|
addq | 0 |
subq | 1 |
andq | 2 |
xorq | 3 |
jXX
指令 | fn |
---|---|
jmp | 0 |
jle | 1 |
jl | 2 |
je | 3 |
jne | 4 |
jge | 5 |
jg | 6 |
CISC和RISC
CISC
基于栈的指令集,程序计数器。
明确的出、入栈指令
算术指令可以访存,地址计算复杂。
条件码是算术和逻辑运算的副作用
RISC
更多的寄存器,没有条件码。
更少更简单的指令
MISP寄存器
HCL
字相等
bool Eq=(A==B)
位多路复用器
bool out=(s&&a)||(!s&&b)
字多路复用器
int Out=[
s:A;
1:B;
]
情况表达式(case语句)
一系列二元组“布尔表达式:整数表达式”, 第一个求值为1 的情况会被选中
顺序执行的处理器
SEQ硬件结构
阶段 | 嘤语 | 作用 |
---|---|---|
取指 | Fetch | 从指令储存器读取指令 |
译码 | Decode | 读程序寄存器 |
执行 | Execute | 计算数值/地址 |
访存 | Memory | 读/写内存数据 |
写回 | Write Back | 写程序寄存器 |
更新PC | PC | 更新程序计数器 |
指令编码的分析
指令字节 icode:ifun
可选的寄存器字节 rA:rB
可选的常数字 valC
指令的执行
OPq
OPq rA,rB | |
---|---|
Fetch | |
.. | |
.. | |
Decode | |
.. | |
Execute | |
.. | |
Memory | |
WriteBack | |
.. | |
PC |