Linux汇编之二进制编码的十进制

汇编 2015年03月17日 ,

Linux汇编二进制编码的十进制

二进制编码的十进制(Binary Coded Decimal, BCD)数据类型在计算机系统中已经存在很久了,BCD格式经常用于简化对使用十进制数字的设备的处理。处理器不是把十进制数字转换为二进制数字以便进行数学操作,然后再转换回十进制;而是按BCD格式保存数字并且执行数学操作。本文中枫竹梦介绍Linux汇编语言(ASM)中BCD如何工作以及处理器如何使用它。

BCD是什么

BCD按照二进制格式对十进制数字进行编码。第个BCD值都是一个无符号8位整数,值的范围是0到9。在BCD中,大于9的8位值被认为是非法的。包含BCD值的字节组合在一起表示十进制的数位。在多字节的BCD值中,最低的字节保存十进制的个位的值,下一个较高位字节保存十位的值,以此类推。如图:

BCD编码

BCD使用整个字节表示每个十进制数位。这样做是浪费了空间,因此打包的BCD被创建出来。打包的BCD允许单一字节包含两个BCD值。字节的低4位包含低位的BCD值,字节的高4位包含高位的BCD值。如下图:

Linux下的BCD编码

即使使用打包的BCD。效率也不高。使用4个字节,打包的BCD只能表示从0到9999的数字。在无符号整数值中,使用4个字节可以表示的最大值是4292967295。

一般的BCD格式只支持无符号整数值,而FPU提供了对带符号整数的支持。

FPU BCD值

FPU寄存器可以用于在FPU之内进行BCD数学运算操作。FPU包含8个80位寄存器(ST0~ST7),还可以保存80位BCD值。使用低位的9个字节存储BCD值,格式是打包BCD,第个字节包含2个BCD值。多数情况下,除了最高位的一位外,不使用FPU寄存器的最高字节,这一位用作符号指示符,1表示负的BCD值,0表示正的BCD值。

为了把BCD值加载到FPU寄存器中,必须使用80位打包的BCD格式的在内存中创建值。值被传送给FPU寄存器后,它就被自动地转换为扩展双精度浮点格式。在FPU中,对数据进行的任何数学操作都是按照浮点格式进行的。当准备从FPU获取结果时,浮点值被转换为80位打包BCD格式。

传送BCD值

IA-32指令集包含处理80位打包BCD值的指令。可以使用FBLDFBSTP指令把80位打包BCD值加载到FPU寄存器中或者从FPU寄存器获取这些值。FPU寄存器的工作方式与通用寄存器不同,8个FPU寄存器的行为类似于内存中的堆栈区域。可以把值压入和弹出FPU寄存器池。ST0引用位于堆栈顶部的寄存器。当值被压入FPU寄存器堆栈时,它被存放在ST0寄存器中,ST0中原来的值被加载到ST1中。

FBLD指令用于把打包的80位BCD值传送到FPU寄存器堆栈中,这的格式很简单:

fbld source

其中source是80位的内存位置。如下程序演示如何将BCD值传送给FPU寄存器并从FPU寄存器中获取BCD值。

# bcd.s - By furzoom @ Mar 15, 2015
.section .data
data1:
.byte 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
data2:
.int 2
.section .text
.globl _start
_start:
nop
fbld data1
fimul data2
fbstp data1

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

该程序创建一个表示十进制1234的简单的BCD值,接着使用FBLD指令将这个值加载到FPU寄存器堆栈的顶部ST0,使用FIMUL指令把ST0寄存器和data2所在内在位置中的整数值相乘,最后使用FBSTP指令把堆栈中新的值传送回data1所在的内存位置。调试运行如下:

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

Breakpoint 1, _start () at bcd.s:11
11        fbld data1
(gdb) x/10xb &data1
0x8049094 <data1>:      0x34    0x12    0x00    0x00    0x00    0x00    0x00    0x00
0x804909c <data1+8>:    0x00    0x00
(gdb) step
12        fimul data2
(gdb) info all
eax            0x0      0
ecx            0x0      0
edx            0x0      0
ebx            0x0      0
esp            0xbfffe7c0       0xbfffe7c0
ebp            0x0      0x0
esi            0x0      0
edi            0x0      0
eip            0x804807b        0x804807b <_start+7>
eflags         0x200212 [ AF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0
st0            1234     (raw 0x40099a40000000000000)
st1            0        (raw 0x00000000000000000000)
st2            0        (raw 0x00000000000000000000)
st3            0        (raw 0x00000000000000000000)
st4            0        (raw 0x00000000000000000000)
st5            0        (raw 0x00000000000000000000)
st6            0        (raw 0x00000000000000000000)
---Type  to continue, or q  to quit---q
Quit
(gdb) step
13        fbstp data1
(gdb) info all
eax            0x0      0
ecx            0x0      0
edx            0x0      0
ebx            0x0      0
esp            0xbfffe7c0       0xbfffe7c0
ebp            0x0      0x0
esi            0x0      0
edi            0x0      0
eip            0x8048081        0x8048081 <_start+13>
eflags         0x200212 [ AF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0
st0            2468     (raw 0x400a9a40000000000000)
st1            0        (raw 0x00000000000000000000)
st2            0        (raw 0x00000000000000000000)
st3            0        (raw 0x00000000000000000000)
st4            0        (raw 0x00000000000000000000)
st5            0        (raw 0x00000000000000000000)
st6            0        (raw 0x00000000000000000000)
---Type  to continue, or q  to quit---q
Quit
(gdb) step
15        movl $1, %eax
(gdb) x/10xb &data1
0x8049094 <data1>:      0x68    0x24    0x00    0x00    0x00    0x00    0x00    0x00
0x804909c <data1+8>:    0x00    0x00
(gdb)

调试结果证明对BCD值处理的成功。

(完)

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

1 篇回应 (访客:1 篇, 博主:0 篇)

  1. 爱城轨 2015-18-03

    谢谢楼主分享。爱城轨,http://www.metro521.com.做中国最大的轨道交通技术分享网站,欢迎站长回访。并想问下站长可以交换友链么?

    #-49楼

插入图片

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

回到顶部