OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6046|回复: 11

一种通过堆栈改变PC程序计数器的方法

[复制链接]

6

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
125
金钱
125
注册时间
2016-8-13
在线时间
27 小时
发表于 2017-4-13 10:33:38 | 显示全部楼层 |阅读模式
在研究多任务操作系统时候,遇到了一个很瓶颈的问题:如何任务切换的时候,C语言是怎么指定程序进入指定的用户程序的?(即编写的多任务死循环函数)
基于以上问题,在通过查找资料,意外发现。OS设计的时候,需要把任务函数地址入栈,那么这个目的是什么呢??看如下网址:
https://zhidao.baidu.com/question/537673906.html
这种方法是通过把函数地址入栈,然后再 RET 便可以跳到 入栈的函数地址执行函数。代码如下:

MOV DPTR,#DELAY    ;DELAY是函数名,DPTR是一个16为的数据指针,而函数名是16位的
;DEC SP            ;网址里的哥们是要把SP减2,我也不知道原因,我没减也没问题
;DEC SP
PUSH DPL           ;先把函数低地址入栈,再高位入栈,51堆栈是8位储存方式
PUSH DPH
RET           ;退出指令





我们分析上面指令, 首先总体思路是:把函数地址入栈,然后调用RET指令,此时,会返回堆栈里储存的PC指针,当然就是我们入栈的函数地址了,这就是堆栈里保存的PC指针。

以上这种方法,就是通过堆栈来改变程序入口地址的方法。UCOS II 、RTX、FREERTOS实时操作系统猜测也是用这种方法,因为他们也要把函数地址入栈。(研究了几天这些源代码,看得懵懵懂懂,不是非常确定)。
另外,附纯汇编的调试源代码,验证这种方法。(LZ已验证)

闪烁灯_汇编.rar

17.82 KB, 下载次数: 313

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

6

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
125
金钱
125
注册时间
2016-8-13
在线时间
27 小时
 楼主| 发表于 2017-4-13 10:35:21 | 显示全部楼层
这种方法,很多人都不知道,资料也找不到,但是感觉还挺有用的。如果说得不对的地方,还望指出。
回复 支持 反对

使用道具 举报

50

主题

1805

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
6661
金钱
6661
注册时间
2016-5-29
在线时间
909 小时
发表于 2017-4-13 12:33:45 | 显示全部楼层
会玩操作系统的都知道.
回复 支持 反对

使用道具 举报

6

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
125
金钱
125
注册时间
2016-8-13
在线时间
27 小时
 楼主| 发表于 2017-4-13 12:51:53 | 显示全部楼层
操作系统 发表于 2017-4-13 12:33
会玩操作系统的都知道.

好吧。我也只是想让不知道的人知道。
回复 支持 反对

使用道具 举报

2

主题

255

帖子

0

精华

高级会员

Rank: 4

积分
821
金钱
821
注册时间
2013-6-5
在线时间
141 小时
发表于 2017-4-13 12:55:17 | 显示全部楼层
liu_z-w 发表于 2017-4-13 10:35
这种方法,很多人都不知道,资料也找不到,但是感觉还挺有用的。如果说得不对的地方,还望指出。

必须要减的,减掉的是你这个函数自身原来要返回的地址。你能行是因为你在主函数里直接使用RET,一般这个方法要在中断中使用,用的是iret。
另外,这个方法很多人都知道,纯用C语言,不用汇编也能实现。
回复 支持 反对

使用道具 举报

50

主题

1805

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
6661
金钱
6661
注册时间
2016-5-29
在线时间
909 小时
发表于 2017-4-13 12:55:56 | 显示全部楼层
你的现在这个操作方法,可能只可以等效于汇编的 JMP,还不足够做成操作系统
回复 支持 反对

使用道具 举报

6

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
125
金钱
125
注册时间
2016-8-13
在线时间
27 小时
 楼主| 发表于 2017-4-13 21:37:23 | 显示全部楼层
zhxzhx 发表于 2017-4-13 12:55
必须要减的,减掉的是你这个函数自身原来要返回的地址。你能行是因为你在主函数里直接使用RET,一般这个 ...

是么。我以前一直认为PC程序计数器无法手动修改,除非C调用函数或者用汇编的跳转指令,C还可以怎么实现这种功能呢?
回复 支持 反对

使用道具 举报

6

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
125
金钱
125
注册时间
2016-8-13
在线时间
27 小时
 楼主| 发表于 2017-4-13 21:39:27 | 显示全部楼层
操作系统 发表于 2017-4-13 12:55
你的现在这个操作方法,可能只可以等效于汇编的 JMP,还不足够做成操作系统

我觉得比JMP好一点吧,只是以前一直不知道有这个方法。
回复 支持 反对

使用道具 举报

2

主题

255

帖子

0

精华

高级会员

Rank: 4

积分
821
金钱
821
注册时间
2013-6-5
在线时间
141 小时
发表于 2017-4-15 18:52:06 | 显示全部楼层
操作系统 发表于 2017-4-13 12:55
你的现在这个操作方法,可能只可以等效于汇编的 JMP,还不足够做成操作系统

JMP 的目标不能动态的改变
回复 支持 反对

使用道具 举报

2

主题

255

帖子

0

精华

高级会员

Rank: 4

积分
821
金钱
821
注册时间
2013-6-5
在线时间
141 小时
发表于 2017-4-15 19:00:44 | 显示全部楼层
liu_z-w 发表于 2017-4-13 21:37
是么。我以前一直认为PC程序计数器无法手动修改,除非C调用函数或者用汇编的跳转指令,C还可以怎么实现这 ...

unsigned char task_id; /*当前活动任务号*/
unsigned char task_sp[MAX_TASKS];   /*任务的栈指针,实际就是每个任务的SP*/
unsigned int task_sleep[MAX_TASKS]; /*任务休眠计时器*/
unsigned char idata task_stack[MAX_TASKS][MAX_TASK_DEP];  /*任务私栈*/

void os_task_switch(void) /*任务切换函数(任务调度器)*/
{
        task_sp[task_id] = SP;
  while(1)
  {
    task_id++;
          if(task_id == MAX_TASKS) task_id = 0;
    if (task_sleep[task_id]==0) break;
  }
        SP = task_sp[task_id];
}

void os_task_load(unsigned int fn, unsigned char tid) /*任务装入函数.将指定的函数(参数1)装入指定(参数2)的任务槽中.*/
{
        task_stack[tid][0] = (unsigned int)fn & 0xff;
        task_stack[tid][1] = (unsigned int)fn >> 8;
        task_sp[tid] = task_stack[tid]+1;  /*准备 RETURN 的数据,SP将等于task_stack[tid][1]的地址*/
  task_sleep[tid]=0;
}
回复 支持 反对

使用道具 举报

2

主题

255

帖子

0

精华

高级会员

Rank: 4

积分
821
金钱
821
注册时间
2013-6-5
在线时间
141 小时
发表于 2017-4-15 19:02:42 | 显示全部楼层
使用
   os_task_load(task1, 0);
   os_task_load(task2, 1);
   os_task_load(task3, 2);
   os_task_load(task4, 3);
   os_task_start(0);
回复 支持 反对

使用道具 举报

6

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
125
金钱
125
注册时间
2016-8-13
在线时间
27 小时
 楼主| 发表于 2017-4-16 00:33:06 | 显示全部楼层
zhxzhx 发表于 2017-4-15 19:02
使用
   os_task_load(task1, 0);
   os_task_load(task2, 1);

可以的。大兄弟。不错。
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 22:36

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表