显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

信息 灵感 创新

III = Information,Inspiration,Innovation

 
 
 
 

日历

 
 
模块内容加载中...
 
 
 
 
 

天气

 
 
模块内容加载中...
 
 
 
 
 
 
 

湖北省 武汉市 天秤座

 发消息  写留言

 
we are 5. Mathematics, Computation, Programming, Engineering, and Making fun of life.
 
近期心愿make it happen, make it happy, make it harmony
博客等级加载中...
今日访问加载中...
总访问量加载中...
最后登录加载中...
 
 
 
 
 
 
 
 

C51生成汇编代码剖析(4)

2017-10-31 17:15:04 阅读48 评论0 312017/10 Oct31

关于指针(2)

前面分析了char类型的指针,由于char类型只占一个字节,因此相对来说容易很多,对于其它类型的指针,又有什么表现呢?

测试了一下int类型,例如:

int* p=0x30;

*p=0x1234;

这两句会产生的汇编代码和前面char的有点差异。

int在C51中是两个字节,在赋值前,将0x1234的高位写入A,低位写入B,然后调用了一个C?ISTPTR的函数,表现形式和char里面调用的C?CSTPTR是类似的。

再看看float类型。

先给出一个浮点数123.456的表示:

可见123.456的十六进制表示是42 F6 E9 79。

C代码:

float* p=0x30;

*p=123.456;

执行的结果是:

显然结果是一致的,检查一下汇编代码,看看是如何实现的。

调用了一个C?LSTKPTR的函数,不过在调用之前,并没有立即数123.456的信息。

跟踪进去,可以发现,又调用到了一个C?LSTKIDATA的函数:

可以观察到是和DPTR相关的,仔细看就知道,实际上是把代码段的数据移动到了存储器中:

观察ROM中的值:

由此可见,浮点数常量,实际上在编译的时候,已经生成了对应的字节,并放在了ROM中,有点类似code类型的数据,而不是像整型数据,是通过指令产生的。

作者  | 2017-10-31 17:15:04 | 阅读(48) |评论(0) | 阅读全文>>

C51生成汇编代码剖析(3)

2017-10-31 10:37:19 阅读83 评论0 312017/10 Oct31

关于指针(1)

测试如下程序生成的汇编代码:

从C代码可知这个程序申明了两个变量以及一个对应的指针,分别让指针指向这两个变量,并修改其值。

在反汇编代码中,可以看到c1的地址是0x08,c2的地址是0x09,看看指针初始化,指向变量的操作:

8:     ptr_c=&c1;

C:0x0009    7B00     MOV      R3,#0x00

C:0x000B    7A00     MOV      R2,#0x00

C:0x000D    7908     MOV      R1,#0x08

可见,使用到了R1、R2和R3共3个寄存器,其中R1中的内容就是c1的地址0x08,而R2和R3中为0。但是这两个地方的含义不大一样。重点在下面:

9:     *ptr_c=0xaa;

C:0x000F    74AA     MOV      A,#0xAA

C:0x0011    12001E   LCALL    C?CSTPTR(C:001E)

这两句是通过指针的方式为其指向的地址空间赋值,显然累加器A中存放了赋值的立即数,但是调用了一个C?CSTPTR的函数,并不是源代码中编写的,因此,肯定是在链接的时候加进去的,看看这段代码的内容(首地址在0x001E):

C?CSTPTR:

C:0x001E    BB0106   CJNE     R3,#0x01,C:0027

作者  | 2017-10-31 10:37:19 | 阅读(83) |评论(0) | 阅读全文>>

C51生成汇编代码剖析(2)

2017-10-28 11:05:32 阅读73 评论0 282017/10 Oct28

关于变量

分析C51编译之后的代码,会将变量存放在哪里。

首先需要说明,编译器如果检测到有申明,但未初始化的变量,会给出警告,并且在生成代码的时候会忽略这些未使用的变量。

例如:

unsigned char a;//仅申明,如果后面一直不使用,就不会有任何与之相关的代码生成

但是:

unsigned char a=12;//申明+初始化,会生成代码

右边可以看到,将12赋值给了存储器0x08中,检查存储器可以证实:

如果再跟一个char b,用负数为其初始化,则可以看到占据的存储器空间是紧跟在a之后,并采用补码的形式表示。

对于像int、long类型的,占据多个字节(int为2字节,long为4字节),摆放地址是高位在前,低位在后,测试如下:

float类型:

这段代码说明了2个问题:

1. 变量所占据的地址,是根据申明的顺序,不是根据初始化的顺序。

2.浮点数按IEEE754规范表示(见下图),并且也是高位在前,低位在后,但写入方式是先写入低位(0x11),最后写入高位(0x0E)。

3. 代码0x0006处,出现的0x80,被反汇编解释为#P0,显然是单片机中的P0扣地址(0x80)。

bit类型

通过测试,bit类型会依次放在存储器第一个可位寻址(20H)的第一位,第二位等。

例如对于两个bit型的变量:

C:0x000F  

作者  | 2017-10-28 11:05:32 | 阅读(73) |评论(0) | 阅读全文>>

C51生成汇编代码剖析(1)

2017-10-28 10:54:57 阅读75 评论0 282017/10 Oct28

研究C51编译生成的汇编代码,有助于学习汇编语言,以及C和汇编的混合编程。

1.最简单的程序

C51中最简单的程序肯定是这个:

看右边反汇编的结果,可以发现,在进入main函数之前,程序会做一些准备工作,例如

C:0x0003    787F     MOV      R0,#0x7F

C:0x0005    E4       CLR      A

C:0x0006    F6       MOV      @R0,A

这三行,相当于是将00写入存储器0x7F中。

C:0x0007    D8FD     DJNZ     R0,C:0006

这一句相当于是将存储器0x00-0x7F中的数据全部清零,即将存储器低128位全部清零,可以查看存储器:

C:0x0009    758107   MOV      SP(0x81),#0x07

则是设置堆栈。

这些工作做完之后,则是一个长跳转到了main函数的入口点0x000F,当然这里什么都没有,只有一个RET。

作者  | 2017-10-28 10:54:57 | 阅读(75) |评论(0) | 阅读全文>>

C程序:查找前n个质数

2017-10-15 16:04:35 阅读83 评论0 152017/10 Oct15

void ListNPrimes(unsigned int n) { unsigned long long *pPrimes=NULL; unsigned long long test; unsigned int cnt,i,primeFlag,sqrt_test; if(n<4) { printf("ListNPrimes:\"n\" should be no less than 4.\n"); return; } pPrimes=(unsigned long long*)calloc(n,sizeof(unsigned long long)); if(!pPrimes) { printf("ListNPrimes:Memory allocation failed.\n"); return; } *pPrimes=2UL; *(pPrimes+1)=3UL; *(pPrimes+2)=5ULL; cnt=3; test=5; while(cnt<n) { test+=2; if((test-1)%6!=0&&(test+1)%6!=0) continue; primeFlag=1; sqrt_test=(unsigned int)sqrt(test);

作者  | 2017-10-15 16:04:35 | 阅读(83) |评论(0) | 阅读全文>>

查看所有日志>>

 
 
 
 
 
 
 
模块内容加载中...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018

注册 登录  
 加关注