问题:已知

struct A

{

char a:2;

unsigned int b:3;

} a;

a.a=6;

a.b=7;

int b,c;

b=a.a;

c=a.b;

调试分析为何输出b为0xFFFFFFE,c为0x7?

下面分析上述问题;

目的:

1. gdb调试命令及汇编环境下调试

2学会在WindowsGDB调试Linux的应用程序及objdump调试

3.分析程序的单步执行,确认每一步的原理;

4.看调试器是如何取得位域的值,如何修改位域的值

环境:

计算机(Windows8.1)、gdb-7.12.1、VMware虚拟机(Ubuntu)eclipse

1、分析程序的单步执行,确认每一步的原理。

(1)通过eclipse打开程序,编译调试。点击window,选择show view 选项,在子菜单中选择Disassembly选项,查看源码的汇编语言。

C语言的位域调试——软件调试

同时点击Register选项,方便查看寄存器变量值。

C语言的位域调试——软件调试

(2)得到源码的汇编代码,单步调试程序,通过汇编语言和寄存器变量的变化确认每一步程序执行的原理。查看eax值在单步机器指令执行后的变化可以采用gdb中的si命令和i r命令,将执行结果输出到exercise1pot1.txt中。

其中部分结果截图如下:

C语言的位域调试——软件调试

15          a.a=6;

详解

eax的值

movzbl 0x14(%esp),%eax

0x14的第一个字节以高位补0的方式放入eax寄存器中

0x0

and $0xfffffffc,%eax

eax中的值与0xfffffffc进行位与操作,将结果存入eax中。所以此操作是将eax的最低2位清空

0x0

or $0x2,%eax

eax中的值与10进行位或操作,将结果存入eax中。也就是给eax的最低2位中写入10。

0x2

mov %al,0x14(%esp)

al(eax的最低8位:0000 0010)中的值回写到0x14的第一个字节中

0x2

第一条赋值语句a.a=6;执行完成。根据汇编语言可以看出这一段实现了截断,再联系前面可知,是由于char a:2;位域a只占了2个比特位。6(110)赋值下来变成了2(10)。再看下一句赋值语句:

16          a.b=7;

详解

eax的值

movzbl 0x14(%esp),%eax

0x14的第一个字节以高位补0的方式放入eax寄存器中

0x2

or $0x1c,%eax

eax中的值与11100进行位或操作,将结果存入eax中。也就是给eax的2-4位中写入111。

0x1e

mov %al,0x14(%esp)

al(eax的最低8位:0001 1110)中的值回写到0x14的第一个字节中

0x1e

第二条赋值语句a.b=7;执行完成。根据汇编语言可以看出这一段实现赋值,而没有发生上面出现的截断,再联系前面可知,是由于char b:3;位域b只占了3个比特位。7111)的二进制表示刚好是3位。再看下一句赋值语句:

18          c=a.a;

详解

eax的值

movzbl 0x14(%esp),%eax

0x14的第一个字节以高位补0的方式放入eax寄存器中

0x1e

shl $0x6,%eax

将eax寄存器中的值左移6位放入eax寄存器中

0x780

sar $0x6,%al

eax寄存器中低八位的值右移6位放入eax寄存器中

0x7fe

movsbl %al,%eax

al寄存器的内容进行符号扩展后放置到edx寄存器中

0xfffffffe

mov %eax,0x18(%esp)

将寄存器eax中的内容(a的地址)传给寄存器中的变量c

0xfffffffe

第三条赋值语句c=a.a执行完成。注意:

C语言的位域调试——软件调试

2.查看调试器是如何取得位域的值,如何修改位域的值。

打开linux终端进行objdump调试,将调试内容输出到exercise1pot1.txt文件中。并打开eclipse查看内存及esp的值。

C语言的位域调试——软件调试

C语言的位域调试——软件调试

通过这里可知结构体大小为四个字节,位域a和b,c和d在结构体中这样存储:

b=7

a=-2 'þ'

1E(16进制)

0

0

0

1

1

1

1

0

C语言的位域调试——软件调试

c

d

FE

FF

FF

FF

07

00

00

00

C语言的位域调试——软件调试

esp值为0xbffff0a0,c的位置为esp+24,大小为4个字节,d的位置存储在esp+28,大小为4个字节,同时可以发现是应该以小端模式来存放的。

C语言的位域调试——软件调试

C语言的位域调试——软件调试

C语言的位域调试——软件调试

从这里可知c和d的类型都是signed int ;

C语言的位域调试——软件调试

C语言的位域调试——软件调试

C语言的位域调试——软件调试

C语言的位域调试——软件调试

由此可以推导位域a类型为signed char型,b类型为unsigned int型。


相关文章: