曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 4826|回复: 0
打印 上一主题 下一主题

扩展整数(带符号与不带符号)

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2009-12-21 10:19:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
内存或者寄存器中表示带符号整数经常是难以识别的,除非知道期望什么。有时候 GNU 调试器能够有所帮助,但是有时候甚至它会混淆,如下例所示:
.section .data

data:
        .int -45
.section .text

.global _start
_start:
        nop
        movl $-345, %ecx
        movw $0xffb1, %dx
        movl data, %ebx
        movl $1, %eax
        int $0x80
在 gdb 中走过 movl data, %ebx 后,用 info reg 命令查看寄存器得到:
ecx            0xfffffea7       -345
edx            0xffb1   65457
ebx            0xffffffd3       -45
上面,EBX 和 ECX 中的值如期望一样,看到了负值,但是在 EDX 寄存器中,我们看到的是正数(原本打算填个正数进去)。这是因为,调试器假设整个 EDX 寄存器包含的是一个双字带符号整数(32位)。但我们在把 0xffb1 送进 EDX 时,0xffb1 是一个单字 (0xffb1),所以 GDB 解释出的信息“错误”了。但是,寄存器中的数据仍然是正确的(0xffb1),之所以被看成是正数,那是因为高一个字被 0 扩展了!所以,像在这样左右为难的情况下,我们需要对整数做正确的扩展。

1、扩展无符号整数
把无符号整数转换为位数更大的值时(比如把字转换为双字),必须确保所有的高位部分都被设置为 0 ,而不是简单的把一个值赋值给另外一个值,比如:
movw %ax, %bx
这样不能确保 EBX 寄存器的高位部分都包含零。为了完成这个操作,必须使用两条指令:
movl $0, %ebx
movw %ax, %ebx
上面第一条指令保证了 EBX 寄存器的每一位都是 0,然后可以安全地把 AX 寄存器中的无符号整数值传给 EBX 寄存器。

但是,Intel 还提供了 MOVZX 指令,简化了上面的操作,格式如下:
movzx source, destination
其中,source 可以是 8 位或 16 位寄存器或者内存位置,destination 可以是 16 位或者 32 位寄存器。如:
.section .text
.global _start
_start:
        nop
        movl $279, %ecx
        movzx %cl, %ebx
        movl $1, %eax
        int $0x80
调试时,在 movl $1, %eax 处下断,运行,然后观察相关寄存器:
ecx            0x117    279
ebx            0x17     23
可以看到,MOVZX 指令只传送了 ECX 寄存器的低位字节,而用 0 填充了 EBX 中的剩余字节,这样就在 EBX 寄存器中生成了 0x17 这个值。

2、扩展带符号整数

扩展带符号整数和扩展无符号整数是不同的。使用 0 填充高位会改变负数的数据值。例如,把 -1 (11111111) 传送给双字会变成 0000000011111111,在带符号整数表示法中它是 +127 ,而不是 -1 。为了使带符号扩展能够起作用,新添加的位必须被设置为 1。因此,新的双字将生成值 1111111111111111 ,这是带符号整数表示法的值 -1,这是正确的。

Intel 提供了 MOVSX 指令可以达到扩展带符号数的功能,它允许扩展带符号整数并且保留符号。如下程序所示:
.section .text
.global _start
_start:
        nop
        movw $-79, %cx
        movl $0, %ebx
        movw %cx, %bx
        movsx %cx, %eax
        movl $1, %eax
        movl $0, %ebx
        int $0x80
使用 gdb 调试时,在 movsx 处下断,运行程序,然后查看 info reg 查看寄存器中的内容:
ecx            0xffb1   65457
此时,ecx 中的内容是 0x0000ffb1,低 16 位包含的值是 0xffb1,它是带符号整数格式 -79。当 CX 寄存器被传送给 EBX 寄存器时,EBX 寄存器包含的值是 0x0000ffb1,它是带符号整数格式 65457 ,这不是我们所期望的。

在使用 MOVSX 把 CX 寄存器传给 EAX 寄存器之后,EAX 寄存器包含的值是 0xFFFFFFB1,它是带符号整数格式的 -79。MOVSX 指令正确地为这个值添加了高位部分的 1 。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-4 01:43 , Processed in 0.067890 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表