IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 汇编变种后缀的应用场景 -> 正文阅读

[C++知识库]汇编变种后缀的应用场景

汇编变种后缀的应用场景

前置知识:

0.C语言数据格式

#include <iostream>
using namespace std;

int main() {
	cout << "sizeof(char)=" << sizeof(char) << endl;
	cout << "sizeof(short)=" << sizeof(short) << endl;
	cout << "sizeof(int)=" << sizeof(int) << endl;
	cout << "sizeof(long)=" << sizeof(long) << endl;
	cout << "sizeof(long long)=" << sizeof(long long) << endl;
	cout << "sizeof(void*)=" << sizeof(void *) << endl;
}

在64位ubuntu上的运行结果

root@deutschball-virtual-machine:/home/deutschball/mydir# g++ test.cpp -o test.out
root@deutschball-virtual-machine:/home/deutschball/mydir# ./test.out
sizeof(char)=1
sizeof(short)=2
sizeof(int)=4
sizeof(long)=8
sizeof(long long)=8
sizeof(void*)=8

在64位windows上的运行结果稍有不同

sizeof(char)=1
sizeof(short)=2
sizeof(int)=4
sizeof(long)=4
sizeof(long long)=8
sizeof(void*)=8

在32位windows上的运行结果

sizeof(char)=1
sizeof(short)=2
sizeof(int)=4
sizeof(long)=4
sizeof(long long)=8
sizeof(void*)=4
操作系统\大小(字节)charshortintlonglong longvoid*
linux64位124888
windows64位124488
windows32位124484

1.寄存器规格

大多数的后缀都与寄存器规格有关,
下图将会被多次用到

在这里插入图片描述

2.寻址方式

image-20220406180238442

mov类

操作数长度相关后缀b,w,l,q

mov类命令的数据流动方向有五种,

立即数->寄存器
寄存器->寄存器
主存  ->寄存器
立即数->主存
寄存器->主存

显然立即数->立即数是不可能的,这里立即数相当于右值,就好比说把5存到6上

并且规定不能从主存直接到主存即主存->主存,必须经过寄存器

数据长度有关的后缀

image-20220406174739043

这里两个字节等于一个字

便于记忆,可以了解后缀的含义:

b:byte,一个字节

w:word,一个字(两个字节)

使用哪种后缀需要与数据流动方向一起决定,具体规则是:

1.主存没有决定后缀的权利

2.如果源或者目的其一是寄存器则根据寄存器大小决定,如果使用的是`%al,%spl`这种单字节寄存器则mov命令用b后缀,
同理如果使 `%rax,%rsp`这种8个字节寄存器则mov命令用q后缀.
如果源和目的都是寄存器则跟随目的寄存器规格

3.寄存器比立即字的优先级高

记住这三条规则才能完成3.2

在这里插入图片描述

1.movl %eax,(%rsp)

在这里插入图片描述

%eax为32位(=4字节=2字)寄存器,

目的(%rsp)是采用简介寻址,实际地址位于内存中,没有发言权,

因此mov的后缀跟随%eav即传送双字,使用l后缀

2.movw (%rax),%dx

image-20220406180020141

(%rax)在内存中,没有发言权,

目的%dx是一个16位(=2字节=1字)寄存器

因此mov的后缀跟随%dx即传送单字,使用w后缀

3.movb $0xFF %bl

在这里插入图片描述

$0xFF是一个立即字,优先级低

目的%bl是一个字节寄存器,优先级高

mov后缀跟随%bl使用b

4.movb (%rsp,%rdx,4) %dl

image-20220406180836564

(%rsp,%rdx,4)在内存上,没有发言权

目的%dl是一个字节寄存器

mov后缀跟随%dl使用b

5.movq (%rdx),%rax

在这里插入图片描述

(%rdx)在内存上,没有发言权

目的%rax是一个四字寄存器

mov后缀跟随%rax使用q

6.movw %dx,(%rax)

image-20220406181231776

%dx是一个单字寄存器

目的(%rax)在内存上,没有发言权

因此mov后缀跟随%dx用w

长度类后缀的其他细节差异

image-20220406191326874

1.movb,movw只会修改目标寄存器的对应低位

2.movl不光会修改目标寄存器的对应低位,并且会将高位全部置零

3.对于64位的立即数,1.只能用movabsq2.将其存到寄存器中,movq只能处理32位的立即数

数据拓展相关后缀z,s

image-20220406193244989

零拓展和符号拓展的区别:

在这里插入图片描述

R(%dl)=AA=10101010符号位为1

第4行符号拓展直接将高位全都置1得到一串F

第5行零拓展直接将高位全都置0得到一串0

有符号数拓展时使用符号拓展

无符号数拓展时使用0拓展,可以理解为无符号拓展

image-20220406200228709

1.首先,使用指针的目的是,使实际操作的地址在内存中,如此需要在寄存器中过度一次,将转型分成两个阶段,即源内存->寄存器寄存器->目的内存两个阶段

2.然后一定注意"当执行强制类型转换即涉及大小变化又涉及C语言中的符号变化时,操作应该先改变大小"

这里"先改变大小"的意思是,无符号源用z,有符号源用s,然后决定大小的后缀看目的的大小

1.long到long

不涉及大小变化,不涉及符号变化,只需要使用传送四字指令movq,两个阶段相同

2.char到int

只涉及大小变化,首先从字节内存到双字寄存器需要符号拓展指令movsbl
然后从双字寄存器到内存根据寄存器规格决定使用双字传送指令movl

3.char到unsigned

既涉及大小变化,又涉及符号变化

首先改变大小,从有符号字节内存到双字寄存器需要符号拓展指令movsbl

然后从双字寄存器到双字内存根据寄存器规格决定使用双字传送指令movl,即目的符号不起作用

char到unsigned int和char到int形成的汇编语言是相同的

这一点可以实验验证

对于char的最小值-128=0x80,如果强制转型到unsigned,可能的结果:

1.首先变化符号,然后变化大小,即首先使用movzbl,然后movl,这样unsigned的值为0x00000080=128

2.首先变化大小,然后变化符号,即首先使用movsbl,然后movl,这样unsigned值为0xFFFFFF80=4294967168

基于上述两种猜想,可以写如下程序验证

image-20220406201752965

证明猜想2是正确的

4.unsigned char到long

既涉及大小变化,又涉及符号变化

首先改变大小,从无符号字节内存到四字寄存器,要使用无符号拓展指令movzbq

然后从四字寄存器到内存,使用四字传送指令movq

然而实际上首先使用的是movzbl

查阅了知乎

然后官方给出的解释:

(Clarification, not an erratum) Figure 3.5.

Although there is an instruction movzbq, the GCC compiler typically generates the instruction movzbl for this purpose, relying on the property that an instruction generating a 4-byte with a register as destination will fill the upper 4 bytes of the register with zeros.

尽管应该使用movzbq指令,但是GCC编译器通常使用movzbl指令来达到相同的目的,

这是因为只要是以寄存器为目的并且生成低位4字节的指令都会将高位的4字节置零

博客上其他人的解释

image-20220406203013260

这就很明白了

5.int到char

只涉及大小转换,大变小直接截取

直接从内存中取出双字数据放到寄存器里然后截取低8位传送给内存

即首先使用movl然后movb

6.unsigned到unsigned char

只涉及大小转换,大变小直接截取

直接从内存中取出双字数据放到双字寄存器然后截取低8位传送给内存

即首先使用movl然后movb

7.char到short

只涉及大小变换,小变大需要拓展

首先使用有符号拓展movsbw将字节数据传送到单字寄存器

然后使用movw从单字寄存器传送到内存

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:05:39  更:2022-04-09 18:09:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:07:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码