Linux汇编之转换

汇编 2015年03月21日 ,

Linux汇编数值类型转换

IA-32指令集包含众多指令,用于把以一种数据类型表示的数据转换为另一种数据类型。程序需要把浮点数据转换为整数值,或者相反的转换的情况并不少见。这些指令用于完成这样的任务。本文中枫竹梦介绍Linux汇编语言(ASM)中如何使用这些转换指令。

轮换指令

不同的数据类型的转换需要不同的指令,下表是相关的转换指令。

指令 转换
CVTDQ2PD 打包双字整数到打包双精度FP(XMM)
CVTDQ2PS 打包双字整数到打包单精度FP(XMM)
CVTPD2DQ 打包双精度FP到打包双字整数(XMM)
CVTPD2PI 打包双精度FP到打包双字整数(MMX)
CVTPD2PS 打包双精度FP到打包单精度FP(XMM)
CVTPI2PD 打包双字整数到打包双精度FP(XMM)
CVTPI2PS 打包双字整数到打包单精度FP(XMM)
CVTPS2DQ 打包单精度FP到打包双字整数(XMM)
CVTPS2PD 打包单精度FP到打包双精度FP(XMM)
CVTPS2PI 打包单精度FP到打包双字整数(MMX)
CVTTPD2PI 打包双精度FP到打包双字整数(MMX, 截断)
CVTTPD2DQ 打包双精度FP到打包双字整数(XMM, 截断)
CVTTPS2DQ 打包单精度FP到打包双字整数(XMM, 截断)
CVTTPS2PI 打包单精度FP到打包双字整数(XMM, 截断)

上表中最后的寄存器表示目标寄存器。最后4条指令是截断的转换,转换为不精确时,向零舍入。其它指令转换不精确时,根据XMM MXCSR寄存器的13位和14位控制进行舍入。

源值可以是内存位置、MMX寄存器(64位值)或者XMM寄存器(64位或者128位值)。

转换范例

下面的程序演示如何使用这些指令。

# conv.s - By furzoom @ Mar 19, 2015
.section .data
value1:
.float 1.25, 124.79, 200.0, -312.5
value2:
.int 1, -435, 0, -25
.section .bss
.lcomm data, 16
.section .text
.globl _start
_start:
nop
cvtps2dq value1, %xmm0
cvttps2dq value1, %xmm1
cvtdq2ps value2, %xmm2
movdqu %xmm0, data

movl $1, %eax
movl $0, %ebx
int $0x80

上述程序在标签value1定义一个打包单精度浮点值,在标签value2定义一个打包双字整数值。将它们进行某种类型转换,调试并查看寄存器的状态如下:

[mn@furzoom asm]$ as -gstabs -o conv.o conv.s
[mn@furzoom asm]$ ld -o conv conv.o
[mn@furzoom asm]$ gdb -q conv
Reading symbols from /home/mn/Desktop/Documents/asm/conv...done.
(gdb) break *_start+1
Breakpoint 1 at 0x8048075: file conv.s, line 13.
(gdb) run
Starting program: /home/mn/Desktop/Documents/asm/conv

Breakpoint 1, _start () at conv.s:13
13        cvtps2dq value1, %xmm0
(gdb) step
14        cvttps2dq value1, %xmm1
(gdb)
15        cvtdq2ps value2, %xmm2
(gdb)
16        movdqu %xmm0, data
(gdb)
18        movl $1, %eax
(gdb) print $xmm0
$1 = {v4_float = {1.40129846e-45, 1.75162308e-43, 2.80259693e-43, -nan(0x7ffec8)},
  v2_double = {2.6524947387115311e-312, -nan(0xffec8000000c8)}, v16_int8 = {1, 0, 0, 0,
    125, 0, 0, 0, -56, 0, 0, 0, -56, -2, -1, -1}, v8_int16 = {1, 0, 125, 0, 200, 0,
    -312, -1}, v4_int32 = {1, 125, 200, -312}, v2_int64 = {536870912001,
    -1340029796152}, uint128 = 0xfffffec8000000c80000007d00000001}
(gdb) print $xmm1
$2 = {v4_float = {1.40129846e-45, 1.7376101e-43, 2.80259693e-43, -nan(0x7ffec8)},
  v2_double = {2.6312747808018783e-312, -nan(0xffec8000000c8)}, v16_int8 = {1, 0, 0, 0,
    124, 0, 0, 0, -56, 0, 0, 0, -56, -2, -1, -1}, v8_int16 = {1, 0, 124, 0, 200, 0,
    -312, -1}, v4_int32 = {1, 124, 200, -312}, v2_int64 = {532575944705,
    -1340029796152}, uint128 = 0xfffffec8000000c80000007c00000001}
(gdb) x /4dw &data
0x80490c0 <data>:       1       125     200     -312
(gdb) 

一般转换将浮点值124.79舍入为125,但是截断转换将其舍入为124。

(完)

如无特别说明,本站文章皆为原创,若要转载,务必请注明以下原文信息:
日志标题:《Linux汇编之转换》
日志链接:http://furzoom.com/linux-asm-convert/
博客名称:枫竹梦

发表评论

插入图片

NOTICE1:请申请gravatar头像,没有头像的评论可能不会被回复!

回到顶部