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 <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)。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • 汇编与机器代码一一对应,但是汇编代码却与高级语言不是一一对应的。 上述为两串代码所对应的机器代码和汇编语言,从其中...
    空城难入_d569阅读 135评论 0 0
  • 1 内存访问指令 1.1 LDR:字数据读取指令 指令语法格式: LDR Rd, <地址>LDR指令用于从地...
    城市的风10阅读 1,622评论 0 0
  • struct和class的区别 1、struct的默认成员权限是public2、class的默认成员权限是priv...
    zhouluyao阅读 1,979评论 0 2
  • 1.c++发展史 c++20.。。。。不断更新 2.cin、cout c++中常使用cin、cout进行控制台的输...
    无涯之涯阅读 223评论 0 0
  • 《C++文章汇总》[https://www.jianshu.com/p/bbd842438420]上一篇文章介绍了...
    一亩三分甜阅读 469评论 0 0