Chinaunix首页 | 论坛 | 博客
  • 博客访问: 487258
  • 博文数量: 104
  • 博客积分: 3045
  • 博客等级: 少校
  • 技术积分: 1230
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-29 10:18
文章分类

全部博文(104)

文章存档

2011年(72)

2010年(1)

2009年(1)

2008年(30)

分类: C/C++

2011-05-05 12:49:26

先看一下例子
#include

int main()
{
int i;
unsigned char *p;
char *p1;
int a[] = {0xffffffff, 0xffffffff, 0xffffffff};
p = a;
p1 = a;
for(i = 0 ; i < 8 ; i++) {
printf(" 0x%02x  0x%02x \n", p[i], p1[i]);
}
}
$ gcc main.c 
main.c: In function ‘main’:
main.c:10: warning: assignment from incompatible pointer type
main.c:11: warning: assignment from incompatible pointer type
$ ./a.out 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
看来是在printf的参数传递过程中出现了问题,%x传递的参数的大小是四个字节,反汇编看一下
¥gcc -S main.c -o main.s
$ vi main.s
.file "main.c"
.section .rodata
.LC0:
.string " 0x%02x  0x%02x \n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $48, %esp
movl $-1, 24(%esp)
movl $-1, 28(%esp)
movl $-1, 32(%esp)
leal 24(%esp), %eax
movl %eax, 40(%esp)
leal 24(%esp), %eax
movl %eax, 44(%esp)
movl $0, 36(%esp)
jmp .L2
.L3:
movl 36(%esp), %eax
addl 44(%esp), %eax
movzbl (%eax), %eax
movsbl %al, %ecx
movl 36(%esp), %eax
addl 40(%esp), %eax
movzbl (%eax), %eax
movzbl %al, %edx
movl $.LC0, %eax
movl %ecx, 8(%esp)
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
addl $1, 36(%esp)
.L2:
cmpl $7, 36(%esp)
jle .L3
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.5 20101112 (Red Hat 4.4.5-2)"
.section .note.GNU-stack,"",@progbits

可见,在printf执行的时候传递的两个参数分别使用了 movsbl 和movzbl,这两个指令有什么差别呢

movsbl、movzbl的区别:
    %dh = 8D
    %eax = 98765432

    movb %dh,%al    //%eax = 9876548D

    movsbl %dh,%eax    //%eax = FFFFFF8D
    movzbl %dh,%eax    //%eax = 0000008D

如果 我们要一个字节一个字节的打印内存的信息的时候,还是需要使用unsigned char 作为指针进行打印比较好。

看一下mips 反汇编的结果
       lw      $2,24($fp)
        slt     $2,$2,8
        beq     $2,$0,$L3
        lw      $3,28($fp)
        lw      $2,24($fp)
        addu    $2,$3,$2
        lbu     $5,0($2)
        lw      $3,32($fp)
        lw      $2,24($fp)
        addu    $2,$3,$2
        lb      $2,0($2)
        la      $4,$LC1
        move    $6,$2
        jal     printf
        lw      $2,24($fp)
        addiu   $2,$2,1
        sw      $2,24($fp)
        b       $L2
看一下arm 平台下运行的结果
# ./a.out 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
# cat /proc/cpuinfo 
Processor       : ARM926EJ-S rev 5 (v5l)
BogoMIPS        : 99.12
Features        : swp half thumb fastmult edsp java 
CPU implementer : 0x41
CPU architecture: 5TEJ
CPU variant     : 0x0
CPU part        : 0x926
CPU revision    : 5

Hardware        : Atmel AT91SAM9260-EK
Revision        : 0000
Serial          : 0000000000000000

再看一下arm 的反汇编
.L3:
        ldr     r3, [fp, #-16]
        mov     r2, r3
        ldr     r3, [fp, #-12]
        add     r3, r2, r3
        ldrb    r3, [r3, #0]    @ zero_extendqisi2
        mov     r1, r3
        ldr     r3, [fp, #-16]
        mov     r2, r3
        ldr     r3, [fp, #-8]
        add     r3, r2, r3
        ldrb    r3, [r3, #0]    @ zero_extendqisi2
        ldr     r0, .L6+4
        mov     r2, r3
        bl      printf
        ldr     r3, [fp, #-16]
        add     r3, r3, #1
        str     r3, [fp, #-16]
arm 平台跟 mips 和 x86 有比较大的差别
LDRB    指令从value 与basereg 将一个字节加载到dest

当然,正如网友说的,
根本原因如下:
%x是无符号整数的16进制,是无符号!而你的printf传递的实际是字符型,于是有一个类型提升的问题。p是无符号数,那么0xff提升为无符号整数仍然是0xff,而p1是有符号的,0xff实际的值是-1.那么对应的无符号整数仍然应该为-1的对应值,也就是0xffffffff。这才是根本原因。
其实对于这个问题根本不需要使用反汇编。C语言基础就解决了!

printf 要打印一个%x的话,要传递一个4字节的数据,而对于singed 和unsigned char 的处理来说将一个char 转化成一个4字节的数据 在x86 平台上有movsbl、movzbl 区别的对待有符号和无符号的数据,但是对于arm 来说,编译器通过Ldr只把一个字节的数据传递到参数里面就行,这个是由于编译器的不同而不同的。我只是想看一下,对于有符号和无符号的数据处理,编译器到底是怎么处理的?为什么要照搬教条性的东西呢?如果按照教条性的东西,为什么有的平台打印会不同呢?


阅读(22761) | 评论(8) | 转发(1) |
1

上一篇:linux 性能分析

下一篇:rpm知识

给主人留下些什么吧!~~

GFree_Wind2011-05-06 14:16:21

zhangyd6: 呵呵,写东西俺比较随意。有的时候遇到问题,直接反汇编,感觉那样看问题很直接。呵呵,不过感觉有的时候辩论很有意思,可以让你理解的更深入了。呵呵.....
以前我不习惯反汇编。因为直接看代码,基本上就看出来了。但是要想深入了解就需要反汇编。

其实我评论的主要目的是因为zhang兄的随意写,让一些初学者会迷惑。其实当时我也很迷惑,按说懂得反汇编并且认真分析的人,不该这样哈

zhangyd62011-05-06 14:05:25

GFree_Wind: 呵呵。真理越辩越明。理解你的意思和目的了。我也受教了。多谢多谢。东我只接触过x86和arm,power平台都没碰过。

Zhang兄,主要是因为直接反汇编而不进行说明,.....
呵呵,写东西俺比较随意。有的时候遇到问题,直接反汇编,感觉那样看问题很直接。呵呵,不过感觉有的时候辩论很有意思,可以让你理解的更深入了。呵呵

GFree_Wind2011-05-06 13:29:50

zhangyd6: 呵呵,确实出现这种打印是因为类型提升。不过,俺表达的意思是,从汇编上看去,如何实现这种区别对待的。记得在Power平台上对于有符号的提升,也是可以更改规则.....
呵呵。真理越辩越明。理解你的意思和目的了。我也受教了。多谢多谢。东我只接触过x86和arm,power平台都没碰过。

Zhang兄,主要是因为直接反汇编而不进行说明,会让读者很迷惑。虽然可以直接知道为啥会有这个现象,但是不知道为什么是这样。而所谓的理论则是告诉这个为什么是这样。也就是说理论逻辑决定了汇编的代码是这样的。

当然,我明白Zhang兄的意思。实际上要看汇编如何处理这个提升。这点,我受教了。感谢你的分享!

zhangyd62011-05-06 12:46:28

GFree_Wind: 如果按照教条性的东西,为什么有的平台打印会不同呢?——不同平台打印不同,确实会这样。因为首先对于数值编码,每个平台会有不同。例如是否采用补码形式等等。.....
呵呵,确实出现这种打印是因为类型提升。不过,俺表达的意思是,从汇编上看去,如何实现这种区别对待的。记得在Power平台上对于有符号的提升,也是可以更改规则的,不过从处理器来说,根本就是使用符号加载命令或者是无符号的加载命令。因为之前看都是国内的教材,所以俺要从根本上说明这个原因。俺觉得根本原因是,对于有符号的处理,要看我的汇编命令如何进行加载。而不是牢记教条。呵呵GFree 兄提得对,不过俺觉得解决问题要追本溯源。所以俺反汇编,看到底是如何处理的。所以,你是从理论上解释了,俺只是罗列了代码,没有解释理论而已。

GFree_Wind2011-05-06 11:46:04

如果按照教条性的东西,为什么有的平台打印会不同呢?——不同平台打印不同,确实会这样。因为首先对于数值编码,每个平台会有不同。例如是否采用补码形式等等。另外,提升的规则,确实不同平台,也有不同的类型提升的方式。