本次笔记内容:
06.寻址模式与数据传输指令等
本次笔记从C语言的经典代码出发,学习汇编语言的接口作业。
在用户层编写程序(不涉及kernel,因此也不涉及保护模式等),x86系统看起来是下述结构:
CPU为Memory提供指令,Memory将Data和Instructions传输给CPU。
C代码
int sum(int x, int y)
{
int t = x + y;
return t;
}
命令行输入:
gcc -O2 -S code.c
对应的x86-32汇编,AT&T汇编格式(与Intel Microsoft汇编格式不同):
sum:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
addl 8(%ebp), %eax
movl %ebp, %esp
popl %ebp
ret
C声明 | Intel数据类型 | 汇编代码后缀 | 大小(字节) |
---|---|---|---|
char | 字节 | b | 1 |
short | 字 | w | 2 |
int | 双字 | l | 4 |
long int | 双字 | l | 4 |
long long int | - | - | 4 |
char * | 双字 | l | 4 |
float | 单精度 | s | 4 |
double | 双精度 | l | 8 |
long double | 扩展精度 | t | 10/12 |
b即byte,w即word;因为是32位机型,long int与int同,long long int没有。
在x86-32中,使用“字(word)”来表示16位整数类型,“双字”表示32位。汇编语言中没有数据类型,一般采用汇编指令的后缀来进行区分。
C代码:
int t = x + y;
为两个整数(32位)相加。
汇编代码:
addl 8(%ebp), %eax
类似于表达式 x += y或者:
int eax;
int *ebp;
eax += ebp[2];
操作数:
把x与y加起来,放在t中(结果存于eax中)。
机器码:
0x401046: 03 45 08
3-字节指令。
数据传送(AT&T语法)
movl Source, Dest:
要注意,对于很多指令,在MIPS或Intel Microsoft中Soure, Dest位置是相反的。
允许的操作数类型
Source Dest 例子 类似的C语言表示
movl {
Imm {
Reg movl $0x4, %eax temp = 0x4;
Mem movl $-147, (%eax) *p = -147;
}
Reg {
Reg movl %eax, %edx temp2 = temp1;
Mem movl %eax, (%edx) *p = temp;
}
Mem {
Reg movl (%eax), %edx temp = *p;
}
}
注意:
(R) : Mem[Reg[R]]
表示寄存器R指定内存地址。
movl (%ecx), %eax
D(R) : Mem[Reg[R] + D]
movl 8 (%ebp), %edx
表示,取ebp的值,加上8,作为地址,取出连续4个byte来(因为mov后缀为l),放在edx中。
void swap (int *xp, int *yp)
{
int t0 = *xp;
int t1 = *yp;
*xp = t1;
*yp = t0;
}
swap:
pushl %ebp
movl %esp, %ebp
pushl %ebx
// 以上为Set Up
movl 12(%ebp), %ecx
movl 8(%ebp), %edx
movl (%ecx), %eax
movl (%edx), %ebx
movl %eax, (%edx)
movl %ebx, (%ecx)
// 以上为Body
movl -4(%ebp), %ebx
movl %ebp, %esp
popl %ebp
ret
// Finsih
如上图,以ebp作为基准。
如上图,假设现在已知ebp存储0x104:
心得:movl (%ecx), %eax表示将ecx的值作为地址,并将其地址对应的值取出来,赋给eax;即,movl其实是对两个地址对应的数值(可是立即数、可是地址)进行操作。
常见形式:
D(Rb, Ri, S) : Mem[Reg[Rb] + S * Reg[Ri]]
其他变形还有:
(Rb, Ri) : Mem[Reg[Rb] + Reg[Ri]]
D(Rb, Ri) : Mem[Reg[Rb] + Reg[Ri] + D]
(Rb, Ri, S) : Mem[Reg[Rb] + S * Reg[Ri]]