前言
本次是该系列的的第0x15篇,本篇介绍了一种将32位有符号数扩展成64位的方法
实验环境:
- Windows10 + VS2022 + masm
0x15
代码片段链接:xorpd | xchg rax,rax 0x15
mov rdx,0xffffffff80000000
add rax,rdx
xor rax,rdx
代码分析
指令依然没啥陌生的,这里使用了一个固定数字:0xffffffff80000000,这个64位数的前33位都是1,后31位都是0,用来与rax进行相加操作
此处rax里装入的输入应该是32位有符号数,这样这个固定数字的设置才显得合理
32位有符号数的最高位是符号位,如果是正数,符号位是0,再次异或这个固定数的时候,前面33位就会都变回0
如果是负数,符号位是1,经过相加后,由于进位以至于前33位的1都变成了0,最终的进位溢出,再次异或的时候,前33位又会变回1
假定输入为:0x80000001,那么接下来的问题就是,0xffffffff80000001和0x80000001表示的值是否相同呢?
测试代码1:
int main(int argv)
{
int a = 0x80000001;
long long b = 0xFFFFFFFF80000001;
printf("32: %d %x\r\n", a, a);
printf("64: %lld %llx", b, b);
return 0;
}
输出结果:
32: -2147483647 80000001
64: -2147483647 ffffffff80000001
结论是,是一样的,所以本篇的主要内容是有符号数32位扩展成64位
测试代码2:
.code
main proc
mov eax, 080000001h
;输入小于等于31位,输出为输入本身
;第32位有值,则结果为负的输入本身
;结果会扩展到64位
mov rdx,0ffffffff80000000h ;前33位都是1
add rax,rdx ;rax = rax + rdx 如果符号位是1(负数),则高32位会因为进位而清零,低31位数据位不变
xor rax,rdx ;rax = rax ^ rdx = (rax + rdx)^rdx 如果是正数,前33位会因为异或变回0,否则会因为异或再次出现
ret
main ENDP
END