因为这里的ax寄存器就是两个地址单元,而mov指令就是等宽传送的。
4)
1.3C语言可以调用asm命令嵌入汇编指令
举个例子:
#include
int main()
{
short x = 0x8543;
short y = 1;
short z = 2;
int p = 0x12345678;
int q = 3;
asm(
"mov -0x8(%rbp),%eax;"
"mov %ax,-0xe(%rbp);"
);
printf("x=%x,y=%d,z=%d\n",x, y, z);
printf("p=%x,q=%d\n", p, q);
return 0;
}
运行后结果为:
x=5678,y=1,z=2
p=12345678,q=3
反汇编为:
#include
int main()
{
400526: 55 push %rbp
400527: 48 89 e5 mov %rsp,%rbp
40052a: 48 83 ec 10 sub $0x10,%rsp
short x = 0x8543;
40052e: 66 c7 45 f2 43 85 movw $0x8543,-0xe(%rbp)
short y = 1;
400534: 66 c7 45 f4 01 00 movw $0x1,-0xc(%rbp)
short z = 2;
40053a: 66 c7 45 f6 02 00 movw $0x2,-0xa(%rbp)
int p = 0x12345678;
400540: c7 45 f8 78 56 34 12 movl $0x12345678,-0x8(%rbp)
int q = 3;
400547: c7 45 fc 03 00 00 00 movl $0x3,-0x4(%rbp)
asm(
"mov -0x8(%rbp),%eax;"
"mov %ax,-0xe(%rbp);"
);
40054e: 8b 45 f8 mov -0x8(%rbp),%eax
400551: 66 89 45 f2 mov %ax,-0xe(%rbp)
printf("x=%x,y=%d,z=%d\n",x, y, z);
400555: 0f bf 4d f6 movswl -0xa(%rbp),%ecx
400559: 0f bf 55 f4 movswl -0xc(%rbp),%edx
40055d: 0f bf 45 f2 movswl -0xe(%rbp),%eax
400561: 89 c6 mov %eax,%esi
400563: bf 14 06 40 00 mov $0x400614,%edi
400568: b8 00 00 00 00 mov $0x0,%eax
40056d: e8 8e fe ff ff callq 400400
printf("p=%x,q=%d\n", p, q);
400572: 8b 55 fc mov -0x4(%rbp),%edx
400575: 8b 45 f8 mov -0x8(%rbp),%eax
400578: 89 c6 mov %eax,%esi
40057a: bf 24 06 40 00 mov $0x400624,%edi
40057f: b8 00 00 00 00 mov $0x0,%eax
400584: e8 77 fe ff ff callq 400400
return 0;
400589: b8 00 00 00 00 mov $0x0,%eax
}
这两个汇编就是把p(0x12345678)复制给x,可以看出数据截断x为0x5678。
2mov和lea的区别
lea是把地址存进去
lea相当于mov的一个特例。
lea针对地址,mov指令针对数据。
3. add,sub,cmp
直接看例子:
#include
int main()
{
int a = 10;
int b = 30;
int x = a + b;
int y = a - b;
if (x < y) {
printf("hello world");
}
return 0;
}
反汇编之后看对应的加法减法和比较。
#include
int main()
{
400526: 55 push %rbp
400527: 48 89 e5 mov %rsp,%rbp
40052a: 48 83 ec 10 sub $0x10,%rsp
int a = 10;
40052e: c7 45 f0 0a 00 00 00 movl $0xa,-0x10(%rbp)
int b = 30;
400535: c7 45 f4 1e 00 00 00 movl $0x1e,-0xc(%rbp)
int x = a + b;
40053c: 8b 55 f0 mov -0x10(%rbp),%edx
40053f: 8b 45 f4 mov -0xc(%rbp),%eax
400542: 01 d0 add %edx,%eax
400544: 89 45 f8 mov %eax,-0x8(%rbp)
int y = a - b;
400547: 8b 45 f0 mov -0x10(%rbp),%eax
40054a: 2b 45 f4 sub -0xc(%rbp),%eax
40054d: 89 45 fc mov %eax,-0x4(%rbp)
if (x < y) {
400550: 8b 45 f8 mov -0x8(%rbp),%eax
400553: 3b 45 fc cmp -0x4(%rbp),%eax
400556: 7d 0f jge 400567
printf("hello world");
400558: bf f4 05 40 00 mov $0x4005f4,%edi
40055d: b8 00 00 00 00 mov $0x0,%eax
400562: e8 99 fe ff ff callq 400400
}
return 0;
400567: b8 00 00 00 00 mov $0x0,%eax
}
4.乘法运算
乘法运算,可能使用加法,移位以及乘法指令去实现,同时乘法有可能存在溢出问题。
看个例子
#include
int main()
{
int x = 3;
int y = 4;
int z1, z2, z3, z4;
unsigned ux = 3,uy = 4,uz;
z1 = x * y;
uz = ux* uy;
z2 = x*3;
z3=x*1024;
z4=x*x+4*x+8;
printf("z1=%d z2=%d z3=%d z4=%d",z1,z2,z3,z4);
return 0;
}
反汇编结果为:
int main()
{
400526: 55 push %rbp
400527: 48 89 e5 mov %rsp,%rbp
40052a: 48 83 ec 30 sub $0x30,%rsp
int x = 3;
40052e: c7 45 dc 03 00 00 00 movl $0x3,-0x24(%rbp)
int y = 4;
400535: c7 45 e0 04 00 00 00 movl $0x4,-0x20(%rbp)
int z1, z2, z3, z4;
unsigned ux = 3,uy = 4,uz;
40053c: c7 45 e4 03 00 00 00 movl $0x3,-0x1c(%rbp)
400543: c7 45 e8 04 00 00 00 movl $0x4,-0x18(%rbp)
z1 = x * y;
40054a: 8b 45 dc mov -0x24(%rbp),%eax
40054d: 0f af 45 e0 imul -0x20(%rbp),%eax
400551: 89 45 ec mov %eax,-0x14(%rbp)
uz = ux* uy;
400554: 8b 45 e4 mov -0x1c(%rbp),%eax
400557: 0f af 45 e8 imul -0x18(%rbp),%eax
40055b: 89 45 f0 mov %eax,-0x10(%rbp)
z2 = x*3;
40055e: 8b 55 dc mov -0x24(%rbp),%edx
400561: 89 d0 mov %edx,%eax
400563: 01 c0 add %eax,%eax
400565: 01 d0 add %edx,%eax
400567: 89 45 f4 mov %eax,-0xc(%rbp)
z3=x*1024;
40056a: 8b 45 dc mov -0x24(%rbp),%eax
40056d: c1 e0 0a shl $0xa,%eax
400570: 89 45 f8 mov %eax,-0x8(%rbp)
z4=x*x+4*x+8;
400573: 8b 45 dc mov -0x24(%rbp),%eax
400576: 83 c0 04 add $0x4,%eax
400579: 0f af 45 dc imul -0x24(%rbp),%eax
40057d: 83 c0 08 add $0x8,%eax
400580: 89 45 fc mov %eax,-0x4(%rbp)
printf("z1=%d z2=%d z3=%d z4=%d",z1,z2,z3,z4);
400583: 8b 75 fc mov -0x4(%rbp),%esi
400586: 8b 4d f8 mov -0x8(%rbp),%ecx
400589: 8b 55 f4 mov -0xc(%rbp),%edx
40058c: 8b 45 ec mov -0x14(%rbp),%eax
40058f: 41 89 f0 mov %esi,%r8d
400592: 89 c6 mov %eax,%esi
400594: bf 34 06 40 00 mov $0x400634,%edi
400599: b8 00 00 00 00 mov $0x0,%eax
40059e: e8 5d fe ff ff callq 400400
return 0;
4005a3: b8 00 00 00 00 mov $0x0,%eax
}
可以看出:
注意:imul用于带符号乘,mul用于无符号乘,不过上面的无符号乘法用的也是imul,因为他只取低32位。
5.控制转移指令
rip 程序指令寄存器,指向下一条待执行指令,如果要跳转的话,就改rip.
转移有两种方法,一种是相对跳转,另一种是绝对跳转。
举个例子:
#include
int sum(int a[], int n)
{
int sum = 0;
for (int i = 0;i < n;i++ ) {
sum += a[i];
}
return sum;
}
int main()
{
int a[4] = {1,2,3,4};
int n =3;
int x;
x =sum (a, n);
printf("sum =%d", x);
return 0;
}
反汇编后:
int sum(int a[], int n)
{
400596: 55 push %rbp
400597: 48 89 e5 mov %rsp,%rbp
40059a: 48 89 7d e8 mov %rdi,-0x18(%rbp)
40059e: 89 75 e4 mov %esi,-0x1c(%rbp)
int sum = 0;
4005a1: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp)
for (int i = 0;i < n;i++ ) {
4005a8: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
4005af: 8b 45 fc mov -0x4(%rbp),%eax
4005b2: 3b 45 e4 cmp -0x1c(%rbp),%eax
4005b5: 7d 1f jge 4005d6 <_Z3sumPii+0x40>
sum += a[i];
4005b7: 8b 45 fc mov -0x4(%rbp),%eax
4005ba: 48 98 cltq
4005bc: 48 8d 14 85 00 00 00 lea 0x0(,%rax,4),%rdx
4005c3: 00
4005c4: 48 8b 45 e8 mov -0x18(%rbp),%rax
4005c8: 48 01 d0 add %rdx,%rax
4005cb: 8b 00 mov (%rax),%eax
4005cd: 01 45 f8 add %eax,-0x8(%rbp)
#include
int sum(int a[], int n)
{
int sum = 0;
for (int i = 0;i < n;i++ ) {
4005d0: 83 45 fc 01 addl $0x1,-0x4(%rbp)
4005d4: eb d9 jmp 4005af <_Z3sumPii+0x19>
sum += a[i];
}
return sum;
4005d6: 8b 45 f8 mov -0x8(%rbp),%eax
}
4005d9: 5d pop %rbp
4005da: c3 retq
00000000004005db :
int main()
{
4005db: 55 push %rbp
4005dc: 48 89 e5 mov %rsp,%rbp
4005df: 48 83 ec 30 sub $0x30,%rsp
4005e3: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
4005ea: 00 00
4005ec: 48 89 45 f8 mov %rax,-0x8(%rbp)
4005f0: 31 c0 xor %eax,%eax
int a[4] = {1,2,3,4};
4005f2: c7 45 e0 01 00 00 00 movl $0x1,-0x20(%rbp)
4005f9: c7 45 e4 02 00 00 00 movl $0x2,-0x1c(%rbp)
400600: c7 45 e8 03 00 00 00 movl $0x3,-0x18(%rbp)
400607: c7 45 ec 04 00 00 00 movl $0x4,-0x14(%rbp)
int n =3;
40060e: c7 45 d8 03 00 00 00 movl $0x3,-0x28(%rbp)
int x;
x =sum (a, n);
400615: 8b 55 d8 mov -0x28(%rbp),%edx
400618: 48 8d 45 e0 lea -0x20(%rbp),%rax
40061c: 89 d6 mov %edx,%esi
40061e: 48 89 c7 mov %rax,%rdi
400621: e8 70 ff ff ff callq 400596 <_Z3sumPii>
400626: 89 45 dc mov %eax,-0x24(%rbp)
printf("sum =%d", x);
400629: 8b 45 dc mov -0x24(%rbp),%eax
40062c: 89 c6 mov %eax,%esi
40062e: bf e4 06 40 00 mov $0x4006e4,%edi
400633: b8 00 00 00 00 mov $0x0,%eax
400638: e8 33 fe ff ff callq 400470
return 0;
40063d: b8 00 00 00 00 mov $0x0,%eax
}
上面的jge就是如果大于等于则跳转,jmp是无条件跳转。
6.过程调用
函数调用过程,看看栈是怎么变化的。
1)保存调用者的ebp
2)建立自己的栈空间
3)为自己的非静态局部变量分配空间
4)函数处理完之后回收栈空间
5) 返回调用者
其中最重要的栈空间就是从rbp到rsp中间的区域,比如下图就是一个栈帧。
具体的细节使用的时候搜索调用约定吧,比如子函数哪几个参数放在什么寄存器,调用者保存还是被调用者保存寄存器的值,以及返回值用什么寄存器都可以在调用约定中找到。举个例子:
int sum(int a1,int a2,int a3,int a4,int a5,int a6,int a7)
{
int sum = 0;
sum += a1;
sum += a2;
sum += a3;
sum += a4;
sum += a5;
sum += a6;
sum += a7;
return sum;
}
反汇编之后:
0000000000400526 <_Z3sumiiiiiii>:
#include
int sum(int a1,int a2,int a3,int a4,int a5,int a6,int a7)
{
400526: 55 push %rbp
400527: 48 89 e5 mov %rsp,%rbp
40052a: 89 7d ec mov %edi,-0x14(%rbp)
40052d: 89 75 e8 mov %esi,-0x18(%rbp)
400530: 89 55 e4 mov %edx,-0x1c(%rbp)
400533: 89 4d e0 mov %ecx,-0x20(%rbp)
400536: 44 89 45 dc mov %r8d,-0x24(%rbp)
40053a: 44 89 4d d8 mov %r9d,-0x28(%rbp)
int sum = 0;
40053e: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
sum += a1;
400545: 8b 45 ec mov -0x14(%rbp),%eax
400548: 01 45 fc add %eax,-0x4(%rbp)
sum += a2;
40054b: 8b 45 e8 mov -0x18(%rbp),%eax
40054e: 01 45 fc add %eax,-0x4(%rbp)
sum += a3;
400551: 8b 45 e4 mov -0x1c(%rbp),%eax
400554: 01 45 fc add %eax,-0x4(%rbp)
sum += a4;
400557: 8b 45 e0 mov -0x20(%rbp),%eax
40055a: 01 45 fc add %eax,-0x4(%rbp)
sum += a5;
40055d: 8b 45 dc mov -0x24(%rbp),%eax
400560: 01 45 fc add %eax,-0x4(%rbp)
sum += a6;
400563: 8b 45 d8 mov -0x28(%rbp),%eax
400566: 01 45 fc add %eax,-0x4(%rbp)
sum += a7;
400569: 8b 45 10 mov 0x10(%rbp),%eax
40056c: 01 45 fc add %eax,-0x4(%rbp)
return sum;
40056f: 8b 45 fc mov -0x4(%rbp),%eax
}
400572: 5d pop %rbp
400573: c3 retq