前言
这一章我们要学习汇编代码,不要求会由C写汇编,但简单的汇编代码要会读,应此,相应转换规则需要熟记
数据格式
C声明 | Intel数据类型 | 汇编代码后缀 | 大小(字节) |
---|---|---|---|
char | 字节 | b | 1 |
short | 字 | w | 2 |
int | 双字 | l | 4 |
long | 四字 | q | 8 |
char* | 四字 | q | 8 |
float | 单精度 | s | 4 |
double | 双精度 | l | 8 |
访问信息
操作数指示符
寄存器
前六个寄存器(%rax, %rbx, %rcx, %rdx, %rsi, %rdi)称为通用寄存器,有其『特定』的用途
%rax(%eax) 用于做累加
%rcx(%ecx) 用于计数
%rdx(%edx) 用于保存数据
%rbx(%ebx) 用于做内存查找的基础地址
%rsi(%esi) 用于保存源索引值
%rdi(%edi) 用于保存目标索引值
传送
对于 movq 指令来说,需要源操作数和目标操作数,源操作数可以是立即数、寄存器值或内存值的任意一种,但目标操作数只能是寄存器值或内存值。指令的具体格式可以这样写 movq [Imm|Reg|Mem], [Reg|Mem],第一个是源操作数,第二个是目标操作数,例如:
*movq Imm, Reg -> mov $0x5, %rax -> temp = 0x5;
movq Imm, Mem -> mov $0x5, (%rax) -> *p = 0x5;
movq Reg, Reg -> mov %rax, %rdx -> temp2 = temp1;
movq Reg, Mem -> mov %rax, (%rdx) -> *p = temp;
movq Mem, Reg -> mov (%rax), %rdx -> temp = p;
接下来看一个具体的例子:
long m12(long x)
{
return x * 12;
}
其对应的汇编是:
leaq (%rdi, %rdi, 2), %rax # t <- x+x*2
salq $2, %rax # return t << 2
FOR循环
long absdiff(long x, long y)
{
long result;
if (x > y)
result = x-y;
else
result = y-x;
return result;
}
对应的汇编结果:(其中 %rdi 中保存了参数 x,%rsi 中保存了参数 y,而 %rax 一般用来存储返回值)
absdiff:
cmpq %rsi, %rdi
jle .L4
movq %rdi, %rax
subq %rsi, %rax
ret
.L4: # x <= y
movq %rsi, %rax
subq %rdi, %rax
ret
goto 语句
例子:
// Do While 的 C 语言代码
long pcount_do(unsigned long x)
{
long result = 0;
do {
result += x & 0x1;
x >>= 1;
} while (x);
return result;
}
// Goto 版本
long pcount_goto(unsigned long x)
{
long result = 0;
loop:
result += x & 0x1;
x >>= 1;
if (x) goto loop;
return result;
}
movl $0, %eax # result = 0
.L2: # loop:
movq %rdi, %rdx
andl $1, %edx # t = x & 0x1
addq %rdx, %rax # result += t
shrq %rdi # x >>= 1
jne .L2 # if (x) goto loop
rep; ret
switch 语句
long switch_eg (long x, long y, long z){
long w = 1;
switch (x) {
case 1:
w = y*z;
break;
case 2:
w = y/z;
// fall through
case 3:
w += z;
break;
case 5:
case 6:
w -= z;
break;
default:
w = 2;
}
return w;
}
栈结构
例子相应代码:
// multstore 函数
void multstore (long x, long, y, long *dest)
{
long t = mult2(x, y);
*dest = t;
}
// mult2 函数
long mult2(long a, long b)
{
long s = a * b;
return s;
}
汇编后:
0000000000400540 <multstore>:
# x 在 %rdi 中,y 在 %rsi 中,dest 在 %rdx 中
400540: push %rbx # 通过压栈保存 %rbx
400541: mov %rdx, %rbx # 保存 dest
400544: callq 400550 <mult2> # 调用 mult2(x, y)
# t 在 %rax 中
400549: mov %rax, (%rbx) # 结果保存到 dest 中
40054c: pop %rbx # 通过出栈恢复原来的 %rbx
40054d: retq # 返回
0000000000400550 <mult2>:
# a 在 %rdi 中,b 在 %rsi 中
400550: mov %rdi, %rax # 得到 a 的值
400553: imul %rsi, %rax # a * b
# s 在 %rax 中
400557: retq # 返回
递归
例子:
long pcount_r(unsigned long x) {
if (x == 0)
return 0;
else
return (x & 1) + pcount_r(x >> 1);
}
对应汇编:
pcount_r:
mov $0, %eax
testq %rdi, %rdi
je .L6
push %rbx
movq %rdi, %rbx
andl $1, %ebx
shrq %rdi
call pcount_r
addq %rbx, %rax
popq %rbx
.L6:
rep; ret
结构体
结构体如果是这样
struct rec
{
int a[4];
size_t i;
struct rect *next;
};
则在机器内部分配内存时为:
如果是这样
struct S1
{
char c;
int i[2];
double v;
} *p;
则为
(参考于小土刀。不周山)
总结
第三章主要是讲一些基础的汇编知识点,教会学生如何看简单的汇编代码。