资讯详情

二进制或汇编中如何判断数据的类型(比如是有符号类型还是无符号类型)

众所周知,二进制代码中的数据没有类型的概念。我们只能知道寄存器或内存中有多少数据。那么,计算机如何判断数据可以操作什么呢?这是编译和汇编时需要完成的工作。通过分析指令或已知函数操作内存地址,我们可以获得一些信息。

以下是几个例子。

例1

int main(){         int count = 1000;         unsigned char loop = 0;         for (; loop < count; loop  ) ;         return 0; } 

其中涉及到 int 类型和 unsigned char 类型比较。以上代码翻译成汇编语言:

00000000000005fa <main>:  5fa:   55                      push   %rbp  5fb:   48 89 e5                mov    %rsp,%rbp  5fe:   c7 45 fc e8 03 00 00    movl   $0x3e8,-0x4(%rbp)  605:   c6 45 fb 00             movb   $0x0,-0x5(%rbp)  609:   0f b6 45 fb             movzbl -0x5(%rbp),?x  60d:   39 45 fc                cmp    ?x,-0x4(%rbp)  610:   7e 0c                   jle    61e <main 0x24>  612:   0f b6 45 fb             movzbl -0x5(%rbp),?x  616:   83 c0 01                add    $0x1,?x  619:   88 45 fb                mov    %al,-0x5(%rbp)  61c:   eb eb                   jmp    609 <main 0xf>  61e:   b8 00 00 00 00          mov    $0x0,?x  623:   5d                      pop    %rbp  624:   c3                      retq  625:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)  62c:   00 00 00  62f:   90                      nop 

可见使用 movzbl 指令先从 -0x5(%rbp) 拷贝到 ?xzbl 后缀表示零扩展从 byte 类型到 long 类型,所以只复制低 8位。对 ?x 加1后再用 mov%al 拷贝回 -0x5(%rbp) ,因为是 %al 所以只有低8位。因此,数据通过指令限制在低8位。

例2

让我们用下面两段代码的汇编代码来看看计算机是如何区分是32位的符号整数和无符号整数。

  • 代码1
#include <stdint.h> int main(){         int32_t count = INT32_MAX;         int32_t loop = 0;         for (; loop < count; loop  ) ;         return 0; } 

对应

00000000000005fa <main>:  5fa:   55                      push   %rbp  5fb:   48 89 e5                mov    %rsp,%rbp  5fe:   c7 45 fc ff ff ff 7f    movl   $0x7fffffff,-0x4(%rbp)  605:   c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%rbp)  60c:   8b 45 f8                mov    -0x8(%rbp),?x  60f:   3b 45 fc                cmp    -0x4(%rbp),?x  612:   7d 06                   jge    61a <main 0x20>  614:   83 45 f8 01             addl   $0x1,-0x8(%rbp)  618:   eb f2                   jmp    60c <main 0x12>  61a:   b8 00 00 00 00          mov    $0x0,?x  61f:   5d                      pop    %rbp  620:   c3                      retq  621:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)  628:   00 00 00  62b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1) 
  • 代码2
#include <stdint.h> int main(){         uint32_t count = UINT32_MAX;         uint32_t loop = 0;         for (; loop < count; loop  ) ;         return 0; } 

对应

00000000000005fa <main>:  5fa:   55                      push   %rbp  5fb:   48 89 e5                mov    %rsp,%rbp  5fe:   c7 45 fc ff ff ff ff    movl   $0xffffffff,-0x4(%rbp)  605:   c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%rbp)  60c:   8b 45 f8                mov    -0x8(%rbp),?x  60f:   3b 45 fc                cmp    -0x4(%rbp),?x  612:   73 06                   jae    61a <main 0x20>  614:   83 45 f8 01             addl   $0x1,-0x8(%rbp)  618:   eb f2                   jmp    60c <main 0x12>  61a:   b8 00 00 00 00          mov    $0x0,?x  61f:   5d                      pop    %rbp  620:   c3                      retq  621:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)  628:   00 00 00  62b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1) 

我们可以从两个代码中看到主要的区别 612 这个地址的内容。对于符号数,比较时使用 jge ,使用无符号数 jae 。原因是计算机不需要数据类型,只要指令正确使用。因此,我们可以知道,从数据的角度来看,我们只能通过指令操作来推断类型。

例3

补充一个例子,可以和之前例2的代码2一起看。

#include <stdint.h> int main(){         uint32_t count = UINT32_MAX;         int32_t loop = 0;         for (; loop < count; loop  ) ;         return 0; } 

对应

00000000000005fa <main>:  5fa:   55                      push   %rbp  5fb:   48 89 e5                mov    %rsp,%rbp  5fe:   c7 45 fc ff ff ff ff    movl   $0xffffffff,-0x4(%rbp)  605:   c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%rbp)  60c:   8b 45 f8                mov    -0x8(%rbp),?x  60f:   39 45 fc                cmp    ?x  60f:   39 45 fc                cmp    ?x,-0x4(%rbp)  612:   76 06                   jbe    61a &l;main+0x20>
 614:   83 45 f8 01             addl   $0x1,-0x8(%rbp)
 618:   eb f2                   jmp    60c <main+0x12>
 61a:   b8 00 00 00 00          mov    $0x0,%eax
 61f:   5d                      pop    %rbp
 620:   c3                      retq
 621:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 628:   00 00 00
 62b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

分析两段汇编代码,其实含义上没有任何区别。对于例2中的代码2, cmp count, loop 时,用的是 jae 指令, loop 无符号大于等于 count 则跳转退出;对于后面这个代码, cmp loop, count 时,用的是 jbe 指令, count 无符号小于等于 loop 则跳转退出。两个意思是一样的。这说明在后面的这个例子中,执行到 loop < count 时,有符号类型变量 int32_t loop 会被强转成无符号类型。

标签: tr35jbe0330电阻

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台