美文网首页
04-汇编指令、引用和Const

04-汇编指令、引用和Const

作者: 一亩三分甜 | 来源:发表于2021-07-18 00:56 被阅读0次

    《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 <iostream>
    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 <iostream>
    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

          本文链接:https://www.haomeiwen.com/subject/qcogpltx.html