4539|3

66

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

【CHECKED】51纯C语言复位函数 [复制链接]

本帖最后由 辛昕 于 2018-9-6 22:03 编辑

以下文字摘自eeworld一帖。帖网址http://topic.eeworld.net/u/20070825/09/5cba9b83-ec38-480a-9d8b-d97eaf48d2d9.html


看过《从单片机指针说到黑客程序》感觉作者说的
unsigned   char   code   rst[]={0xe4,0xc0,0xe0,0xc0,0xe0,0x32};   //   复位代码
(*((void   (*)())(&rst)))();
反汇编后ljmp到一个奇怪的地址去,不明白作者什么意思。
我的反汇编是把rst的地址传给R1,R2,然后把R1,R2分别传到DPH,DPL,然后CLR   A   
JMP   @A+DPTR
跳到rst的地址去了,没见到奇怪的地址啊!!!
有人知道的话告诉我啊?!!


原文如下:

从单片机指针说到黑客程序

作者www.1piao.com/wlg.asp
2004年7月的一天,在电子BBS讨论区上溜达,看到一个有趣的帖子,整个帖子内容如下:

纯C51复位功能函数:一个大三学生,让人又爱又怕

现单列复位部分如下:

main()

{

      unsigned   char   code   rst[]={0xe4,0xc0,0xe0,0xc0,0xe0,0x32};     //   复位代码

      (*((void   (*)())(rst)))();     //   执行上一行代码,将rst数组当函数调用

}

本来我告诉他嵌入如下代码:

clr   a

push   acc

push   acc

reti

结果他却玩了前面哪一段,而数组rst[]中的内容恰恰是上面的汇编机器码,他的做法是将
rst数组的数据当作代码保存,然后采用绝对地址方式指向该数组,将该数组中的代码当作
函数来运行。居然通过了!

我觉得有问题,我说即使如此,那绝对地址调用也应该写成(*((void   (*)())(&rst)))()   
才对呀,结果他反驳说,那样的话,rst的地址就会当成参数传递给这个绝对地址函数,而
实际LJMP调用的地址并非rst的地址,而是一个不确定的地址。于是我按照自己的说法尝试
了一下,看看汇编结果,还真的是将rst的地址传递给了R1   R2,而绝对函数最终LJMP到了
一个莫名其妙的地址上去了,死翘!

看来C真是一匹不容易驾驭的野马,这个大三学生理解力在我之上,我30多岁的人了,干了
这么多年还没他的境界呢,唉,人家才学了几天啊,翻了几天书就这么厉害了,服了!

  

l                   首先分析帖子的C语言代码

第一句定义一个数组rst[],数组内数据就是完成复位功能的汇编机器码,具体对应关系
为:clr   a   ==   0xe4、push   acc   ==   0xc0,0xe0、reti   ==0x32

第二句是一个函数指针的用法,函数指针用法稍微有点复杂,可参看本人著的书,,以
下为快速入门讲解。

定义一个返回值是空函数指针的定义形式如下:

void   (*p)   (   )

当把函数指针赋值后,就能通过函数指针调用函数,调用形式如下,

            (*p)   (   );

或等价的简化形式:

p   (   );

假设rst就是函数指针,则如下调用形式就可以令单片机复位再起。

(*rst   )   (   );     

但可惜,rst不是函数指针,而是数组名,虽然两者都是地址,但不可直接调用数组名。

如同把char型变量a赋值给int型变量b,(int)   表示强制类型转换:

b   =   (int)   a

函数指针的强制类型转换公式如下(C语言的哲学是定义形式和使用一致):

(     (void   (*)()     )   rst   

这样经过转换后的rst就可以当作函数指针使用了,简单的调用形式如下:

#define     K           (     (void   (*)(   )     )   rst

(*K)   (   )

或:

(           *   (     void   (*)(   )     )rst             )   (   );

这样的语句就完成复位再启功能了。类型转换符()的优先级跟指针运算符*的优先级相同,
二者的结合方向是自右至左,所以上述语句就能完成复位功能了。保险起见有些程序员常
常喜欢再加个括号:

#define     K           (       (     (void   (*)(   )     )   rst       )

(*K)   (   )



(           *(       (     void   (*)(   )     )rst       )         )   (   );

  

由于没有输入参数,上述复位代码更严谨的写法是:   

#define     K           (       (     (void   (*)(void   )     )   rst       )

(*K)   (   )



(           *(       (     void   (*)(void   )     )rst       )         )   (   );

  

l                   关于帖子作者的解释

千万不要犯“&rst”形式的错误,对于一维数组而言,数组名rst就代表地址。以下二者等
价,更常用的是等式左边的形式:

rst   ==   &rst[0]

整个函数指针无所谓参数传递,只是把rst当作程序执行地址调用而已,那个学生的解释也
有问题。

还有一点必须提及,不是说能通过编译,甚至生成正确代码,就表示某语句一定是对的。
对很复杂的语句,要考虑到编译器不严格甚至出错的可能性。

  

l                   哈佛结构和一个蠕虫病毒

请注意,定义数组rst[]时用了关键字code,这是C51特有的关键字,意味着把数组定义到
程序空间。标准C是没有关键字code的。

哈佛结构和普林斯顿结构:

哈佛结构——程序空间和存储空间分开的。C51算是不太严格的哈佛结构——虽地址线分
开,但数据线没有分开。DSP是增强的哈佛结构。

PC电脑上奔腾CPU是普林斯顿结构——数据空间和程序空间统一编址。

  

如果数组rst[]数据的汇编机器码是删除文件的机器码,这算不算是病毒?

曾经流行过一种蠕虫病毒,其发作机理采取的就是将恶意代码保存成文本文件,然后通过
指针调用执行这个文本,很多杀毒程序也不会查询文本文件。

程序也罢,数据也罢都是二进制形式,如果数据空间和程序空间是统一编码的,   数据当然
可以当作程序运行。

在这一点上,相对而言,哈佛结构的CPU安全性会好一点点。但嵌入式应用少有病毒,一般
不用关心。

  

l                   单片机复位的更好方法

帖子中汇编语言解释如下:

clr   a                                             //清除ACC=0

push   acc                               //压0到堆栈——8位

push   acc                               //再压0到堆栈——再8位

reti                                                 //返回到0地址,从而执行。

帖子作者的这种复位方法比较麻烦,更加简单的复位写法是(摘自《C缺陷与陷阱》):

(           *   (     void   (*)(   )     )0             )   (   );

本句的分析方法同上,但更加精炼,没有多余的汇编语句。

  

上述复位的方法可称为软件复位。

软件复位跟真正上电复位有很大差别:上电复位时大部分寄存器都有确定的复位值;软件
复位则只相当于从0地址开始执行而已,寄存器不会变为确定的复位值。

如果用户要编程实现上电复位这种情况,在程序中不要踢看门狗即可。大部分单片机都有
看门狗吧。

  

l                   附录

笔者精于DSP   C24xx,但不太懂C51;读者应能从函数指针的定义和引用中看出来,C语言的
设计哲学是使用形式和定义形式一致,虽然这一点饱受质疑。

如果你觉得鸡蛋好吃时,不必认识那只母鸡;但如果你觉得本文不错,请来笔者网站坐坐
www.1piao.com/wlg.asp
此帖出自编程基础论坛

最新回复

1311  详情 回复 发表于 2017-11-13 17:16

赞赏

1

查看全部赞赏

点赞 关注
 

回复
举报

78

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
不错。不过检查严格的编译器是不会编译通过的。
数组名居然当函数指针使。
此帖出自编程基础论坛
 
 
 

回复

78

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
我是来认识 你的呵呵
此帖出自编程基础论坛
 
 
 

回复

7815

帖子

56

TA的资源

裸片初长成(中级)

4
 
1311
此帖出自编程基础论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表