04-汇编指令、引用和Const

《C++文章汇总》
上一篇介绍了引用和汇编《03-Reference、汇编》,本文介绍汇编其他指令、引用和Const。

1.x64汇编要点总结

◼mov dest, src
将src的内容赋值给dest,类似于dest = src
◼[ 地址值 ]
中括号[ ]里面放的都是内存地址
◼word是2字节,dword是4字节(double word),qword是8字节(quad word) ◼call 函数地址
调用函数
◼lea dest, [ 地址值 ]
将地址值赋值给dest,类似于dest = 地址值
◼ret 其实内部也包含jump功能
函数返回
◼xor op1, op2
将op1和op2异或的结果赋值给op1,类似于op1 = op1 ^ op2
◼add op1, op2
类似于op1 = op1 + op2
◼sub op1, op2
类似于op1 = op1 - op2
◼inc op
自增,类似于op = op + 1
◼dec op
自减,类似于op = op – 1
◼jmp 内存地址
跳转到某个内存地址去执行代码 j开头的一般都是跳转,大多数是带条件的跳转,一般跟test、cmp等指令配合使用
◼ 权威参考:Intel白皮书 https://software.intel.com/en-us/articles/intel-sdm

函数的返回值放在eax中


图片.png

2.Jump Condition Code

01、 JE, JZ 结果为零则跳转(相等时跳转) ZF=1
equal zero
02、 JNE, JNZ 结果不为零则跳转(不相等时跳转) ZF=0
not equal not zero
03、 JS 结果为负则跳转 SF=1
sign(有符号\有负号)
04、 JNS 结果为非负则跳转 SF=0
not sign(无符号\无负号)
05、 JP, JPE 结果中1的个数为偶数则跳转 PF=1
parity even
06、 JNP, JPO 结果中1的个数为偶数则跳转 PF=0
parity odd
07、 JO 结果溢出了则跳转 OF=1
overflow
08、 JNO 结果没有溢出则跳转 OF=0
not overflow
09、 JB, JNAE 小于则跳转 (无符号数) CF=1
below not above equal <
10、 JNB, JAE 大于等于则跳转 (无符号数) CF=0
not below above equal >=
11、 JBE, JNA 小于等于则跳转 (无符号数) CF=1 or ZF=1
below equal not above <=
12、 JNBE, JA 大于则跳转(无符号数) CF=0 and ZF=0
not below equal above >
13、 JL, JNGE 小于则跳转 (有符号数) SF≠ OF
little not great equal <
14、 JNL, JGE 大于等于则跳转 (有符号数) SF=OF
not little great equal >=
15、 JLE, JNG 小于等于则跳转 (有符号数) ZF=1 or SF≠ OF
little equal not great <=
16、 JNLE, JG 大于则跳转(有符号数) ZF=0 and SF=OF
not little equal great >

CPU架构决定无法mov 内存到内存,要通过寄存器来进行运算中转
mov带单位,取数据,取多少个字节,lea不带单位,lea赋值内存地址,指针牵扯到取地址值,标记是lea eax,[ebp-0Ch],不能写成mov eax ebp-0Ch,mov指令不能做运算,但可以

sub ebp,0CH//会改掉ebp的值
mov eax,ebp

指针变量赋值

//int age = 3;
//ebp-0Ch是age的地址值
008519C2 mov dword ptr [ebp-0Ch],3

//eax == ebp-0Ch,存放着age的地址值
008519C9 lea eax,[ebp-0Ch]
//ebp-18h是指针变量p的地址值
//将age的地址值存放到指针变量p所在的存储空间
//int *p = &age;
008519CC mov dword ptr [ebp-18h],eax

//*p = 5
//将age的地址值存放到eax
008519CF mov eax,dword ptr [ebp-18h]
//age = 5
008519D2 mov dword ptr [eax],5

指针变量的地址值,另外一个变量的地址值赋值给指针变量去存储
lea eax,[ebp-0Ch]
mov dword ptr [ebp-18h],eax
如下图:引用的内存汇编和指针变量一模一样


image

3.引用

A.结构体引用

#include 
using namespace std;
struct Date {
    int year;
    int month;
    int day;
};
int main(int argc, const char * argv[]) {
    Date d = {2011,1,5};
    Date &ref = d;
    ref.year = 2014;
    
    getchar();
    return 0;
}

B.指针引用

int main(int argc, const char * argv[]) {
    int age = 10;
    int *p = &age;
    int *&ref = p;
    *ref = 30;
    int height = 30;
    ref = &height;
    
    getchar();
    return 0;
}

C.数组引用

int main(int argc, const char * argv[]) {
    int array[] = {1,2,3};
    int (&arr)[3] = array;
    
    int *p;
    //指针数组
    int *a[3] = {p,p,p};
    //数组指针:指向数组的指针
    int (*ar)[3] = &array;
    
    getchar();
    return 0;
}

不存在引用的引用,指向引用的指针,引用数组

D.常引用(Const Reference)

◼ 引用可以被const修饰,这样就无法通过引用修改数据了,可以称为常引用

int main(int argc, const char * argv[]) {
    int age = 10;
    const int &ref = age;
    const int *p = &age;
//    ref = 30;
//    *p = 30;
    cout << ref << endl;
    cout << *p << endl;
    getchar();
    return 0;
}
//输出
10
10

◼ const、指针、引用

int main(int argc, const char * argv[]) {
    int height = 20;
    int age = 10;
    
    //ref1不能修改指向,但是可以通过ref1间接修改指向的变量的值
//    int& const ref1 = age;const可以直接去掉,引用本来就不能修改指向
//    ref1 = 30;不报错
    //ref2不能修改指向,不可以通过ref2间接修改指向的变量的值
    int const &ref2 = age;
//    ref2 = 30;报错
    
    //p1不能修改指向,可以利用p1间接修改指向的变量
    int * const p1 = &age;
    *p1 = 40;
    
    //p2可以修改指向,不可以利用p2间接修改指向的变量
    int const *p2 = &age;
//    *p2 = 50;报错
    p2 = &height;
    
    getchar();
    return 0;
}

const必须写在&符号的左边,才能算是常引用
◼ const引用的特点
可以指向临时数据(常量、表达式、函数返回值等)
可以指向不同类型的数据
作为函数参数时(此规则也适用于const指针)
✓ 可以接受const和非const实参(非const引用,只能接受非const实参)
✓ 可以跟非const引用构成重载

int func(){
    return 8;
}
int sum(int &v1,int &v2){
    cout << "sum(int &v1,int &v2)" << endl;
    return v1 + v2;
}
int sum(const int &v1,const int &v2){
    cout << "sum(const int &v1,const int &v2)" << endl;
    return v1 + v2;
}

int main(int argc, const char * argv[]) {
    //非const实参
    int c = 10;
    int d = 20;
    sum(c, d);
    
    //const实参
    const int e = 10;
    const int f = 20;
    sum(e, f);
    
    sum(10, 20);
    
    int a = 1;
    int b = 2;
    const int &ref = 30;
    const int &ref0 = a + b;
    const int &ref1 = func();
    
    int age = 10;
    const double &ref3 = age;
    
    getchar();
    return 0;
}
//输出
sum(int &v1,int &v2)
sum(const int &v1,const int &v2)
sum(const int &v1,const int &v2)

◼ 当常引用指向了不同类型的数据时,会产生临时变量,即引用指向的并不是初始化时的那个变量

I.常引用ref指向了相同类型数据

int main() {
    int age = 10;
    const int &ref = age;
    age = 30;
    cout << "age is " << age << endl;
    cout << "ref is " << ref << endl;
    getchar();
    return 0;
}
//输出
age is 30
ref is 30

查看汇编,age的值变为了30,ref的值也变为了30

//int age = 10;
mov dword ptr [ebp-0Ch],0Ah
//age的内存地址给到eax
lea eax,[ebp-0Ch]
//[ebp-18h]这段内存空间存放age的内存空间[ebp-0Ch]
mov dword ptr [ebp-18h],eax
//30赋值给[ebp-0Ch]内存地址
mov dword ptr [ebp-0Ch],1Eh

II.常应用ref指向了不同类型数据

#include 
using namespace std;

int main() {
    /*
    int age = 10;
    const int &ref = age;
    age = 30;
    cout << "age is " << age << endl;
    cout << "ref is " << ref << endl;
     */
    int age = 10;
    const long &ref = age;
    age = 30;
    cout << "age is " << age << endl;
    cout << "ref is " << ref << endl;
    getchar();
    return 0;
}
//输出
age is 30
ref is 10

查看汇编,age的值变为了30,而引用ref没有变,在一块新的内存空间中存储

//int age = 10;
mov dword ptr [ebp-0Ch],0Ah
//将10取出来给eax
mov eax,dword ptr [ebp-0Ch]
//将eax给到[ebp-24h]这段内存空间,相当于temp
mov dword ptr [ebp-24h],eax
//将[ebp-24h]这段内存空间 temp给到ecx
lea ecx,[ebp-24h]
//将ecx里面的内存地址的值取出来给到[ebp-18h]
mov dword ptr [ebp-18h],ecx
//将30给到[ebp-0Ch],age就变化了,ref没有变化
mov dword ptr [ebp-0Ch],1Eh

E.不同的编程语言转成的汇编是一样的吗?

Java,C++,OC,Swift写代码--->汇编机器码取决于CPU架构(X86,ARM)。

你可能感兴趣的:(04-汇编指令、引用和Const)