汇编变种后缀的应用场景

汇编变种后缀的应用场景

前置知识:

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从单字寄存器传送到内存

  • 11
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灰球球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值