找回密码
 立即注册
楼主: 杨***

STC单片机 uC/OS-II核心技术(12):关于临界区保护和函数可重入的测试题

[复制链接]

该用户从未签到

63

主题

703

回帖

1万

积分

荣誉版主

积分
10908
 楼主| 发表于 2024-3-23 23:44:56 | 显示全部楼层
CosyOS 发表于 2024-3-23 23:26
首先声明:我所说的方法仅适用于本次讨论的题目,如果换一个题目可能根本就不行了,
具有很强的针对性。

“memcpy当然是可重入的了”,怎么证明?可否将反汇编的分析分享给大家

点评

有疑虑的朋友自己反汇编看下吧  详情 回复 发表于 2024-3-23 23:46
回复 支持 反对 送花

使用道具 举报

  • TA的每日心情
    奋斗
    昨天 12:52
  • 签到天数: 175 天

    [LV.7]常住居民III

    5

    主题

    580

    回帖

    2355

    积分

    荣誉版主

    积分
    2355
    发表于 2024-3-23 23:45:49 | 显示全部楼层
    杨为民 发表于 2024-3-23 23:39
    你觉得“memcpy”函数是可重入的或者是不可重入的?

    “memcpy”函数如果是不可重入的,那就没有解决问题

    截图202403232345379214.jpg

    点评

    这个证明好!这是C51的标准库函数,LAOXU白忙活了,LAOXU老师的全称否定也被打破了。  详情 回复 发表于 2024-3-23 23:52
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 12:52
  • 签到天数: 175 天

    [LV.7]常住居民III

    5

    主题

    580

    回帖

    2355

    积分

    荣誉版主

    积分
    2355
    发表于 2024-3-23 23:46:41 | 显示全部楼层
    杨为民 发表于 2024-3-23 23:44
    “memcpy当然是可重入的了”,怎么证明?可否将反汇编的分析分享给大家

    有疑虑的朋友自己反汇编看下吧

    点评

    你好 ! 有一个问题, 一直想和你核实, 你在 CosyOS中, PendSV_Handler 使用INT0中断,是否意味着用户不能使用 P32(INT0), 作为通用 I/O口了.  详情 回复 发表于 2024-3-24 06:58
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    63

    主题

    703

    回帖

    1万

    积分

    荣誉版主

    积分
    10908
     楼主| 发表于 2024-3-23 23:52:04 | 显示全部楼层

    这个证明好!这是C51的标准库函数,LAOXU白忙活了,LAOXU老师的全称否定也被打破了。

    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 00:57
  • 签到天数: 148 天

    [LV.7]常住居民III

    39

    主题

    889

    回帖

    4154

    积分

    荣誉版主

    积分
    4154
    发表于 2024-3-24 01:47:08 | 显示全部楼层
    CosyOS 发表于 2024-3-23 23:26
    首先声明:我所说的方法仅适用于本次讨论的题目,如果换一个题目可能根本就不行了,
    具有很强的针对性。

    我随手例了一个不可重入函数的例子, 你改换成其他可重入函数. 当然没事了

    这跟我将 strncpy 函数, 改写成可重入函数. 其实是一回事, 对吗?

    点评

    是的  发表于 2024-3-24 02:04
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 00:57
  • 签到天数: 148 天

    [LV.7]常住居民III

    39

    主题

    889

    回帖

    4154

    积分

    荣誉版主

    积分
    4154
    发表于 2024-3-24 01:51:24 | 显示全部楼层
    缓冲区操作 和 字符串操作 标淮库程序, 全部改写成 可重入 类型 !
    https://www.stcaimcu.com/forum.php?mod=viewthread&tid=7083
    (出处: 国芯论坛-STC全球32位8051爱好者互助交流社区)

    所含函数文件例表, 除 strtok 函数之外, 其他函数都是可重入的 !
    新增 可重入的 strtok_s 函数 !

    #pragma SAVE
    #pragma REGPARMS
    extern char *strcat (char *s1, char *s2);
    extern char *strncat (char *s1, char *s2, int n);

    extern char strcmp (char *s1, char *s2);    // (char *R0R4R5, char *R1R2R3)
    extern char strncmp (char *s1, char *s2, int n);

    extern char *strcpy (char *s1, char *s2);        // (char *R0R4R5, char *R1R2R3); *s2-->*s1
    extern char *strncpy (char *s1, char *s2, int n);

    extern int strlen (char *);

    extern char *strchr (const char *s, char c);        // (const char *R1R2R3, char R5)
    extern int strpos (const char *s, char c);                // (const char *R1R2R3, char R5)
    extern char *strrchr (const char *s, char c);        // (const char *R1R2R3, char R5)
    extern int strrpos (const char *s, char c);                // (const char *R1R2R3, char R5)

    extern int strspn (char *s, char *set);
    extern int strcspn (char *s, char *set);
    extern char *strpbrk (char *s, char *set);
    extern char *strrpbrk (char *s, char *set);
    extern char *strstr  (char *s, char *sub);
    extern char *strtok  (char *str, const char *set);
    extern char *strtok_s  (char *str, const char *set, char **str_p);    // 新增

    extern char memcmp (void *s1, void *s2, int n);    // (void *R0R4R5, void *R1R2R3, int R6R7)
    extern void *memcpy (void *s1, void *s2, int n);   // (void *R0R4R5, void *R1R2R3, int R6R7); *s2-->*s1
    extern void *memchr (void *s, char val, int n);           // (void *R1R2R3, char R5, int R6R7)
    extern void *memccpy (void *s1, void *s2, char val, int n);                                                                   // *s2-->*s1
    extern void *memmove (void *s1, void *s2, int n);  // (void *R0R4R5, void *R1R2R3, int R6R7); *s2-->*s1
    extern void *memset  (void *s, char val, int n);   // (void *R1R2R3, char R5, int R6R7)
    #pragma RESTORE
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 00:57
  • 签到天数: 148 天

    [LV.7]常住居民III

    39

    主题

    889

    回帖

    4154

    积分

    荣誉版主

    积分
    4154
    发表于 2024-3-24 02:16:39 | 显示全部楼层
    这是我用宏重新命名的 STRING2.H文件, 注意: 加/* */的函数. 原来都是利用 DATA 来传递参数的, 是不可重入的, 有十几个.

    我全部都改写成真正标准的 可重入的函数, 利用SP堆栈来传递参数, 没有使用 Keil C51 可重入数据模拟栈(特别占CODE容量)

    由于全部库函数都用汇编特别优化, 使得 改写后的 可重入库函数的 CODE长度, 比原来 Keil 库, 更加短小精练.


    原  Keil 库,  有一处 BUG !  是分析 汇编代码时发现的, 本新库中, 已加以更正.


    /*--------------------------------------------------------------------------
    STRING2.H

    String functions.
    Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc.
    All rights reserved.
    --------------------------------------------------------------------------*/

    #ifndef __STRING2_H__
    #define __STRING2_H__

    #ifndef _SIZE_T
    #define _SIZE_T
    typedef unsigned int size_t;
    #endif

    #ifndef NULL
    #define NULL ((void *) 0L)
    #endif

    #pragma SAVE
    #pragma REGPARMS

    extern char *pploadlp (long l, char **p);
    extern char *ploadcp (char c, char *s);
    extern int  iloadcp (char c, char *s);
    extern char cloadcp (char c, char *s);
    extern char *ploadp (char *s);
    extern int  iloadp (char *s);
    extern char cloadp (char *s);

    /* extern char *strcat (char *s1, char *s2); */
    #define  strcat(dst, src)                                strcat1a ((long)src, dst)
    extern char *strcat1a (long dst, char *src);

    /* extern char *strncat (char *s1, char *s2, int n); */
      #define  strncat(dst, src, n)                        (!(ACC^ACC) ? ploadp (src) : strncat1 (n, dst))
    extern char *strncat1 (int n, char *dst);

    extern char strcmp (char *s1, char *s2);    // (char *R0R4R5, char *R1R2R3)
    /* extern char strncmp (char *s1, char *s2, int n); */
      #define  strncmp(s1, s2, n)                        (char)(!(ACC^ACC) ? cloadp (s1) : strncmp1 (n, s2))
    extern char strncmp1 (int n, char *s2);

    extern char *strcpy (char *s1, char *s2);        // (char *R0R4R5, char *R1R2R3); *s2-->*s1
    /* extern char *strncpy (char *s1, char *s2, int n); */
      #define  strncpy(dst, src, n)                        (!(ACC^ACC) ? ploadp (dst) : strncpy1 (n, src))
    extern char *strncpy1 (int n, char *src);

    extern int strlen (char *);

    extern char *strchr (const char *s, char c);        // (const char *R1R2R3, char R5)
    extern int strpos (const char *s, char c);                // (const char *R1R2R3, char R5)
    extern char *strrchr (const char *s, char c);        // (const char *R1R2R3, char R5)
    extern int strrpos (const char *s, char c);                // (const char *R1R2R3, char R5)

    /* extern int strspn (char *s, char *set); */
    #define  strspn(s, set)                                strspn1a ((long)s, set)
    extern int strspn1a (long s, char *set);

    /* extern int strcspn (char *s, char *set); */
    #define  strcspn(s, set)                                strcspn1a ((long)s, set)
    extern int strcspn1a (long s, char *set);

    /* extern char *strpbrk (char *s, char *set); */
    #define  strpbrk(s, set)                                strpbrk1a ((long)s, set)
    extern char *strpbrk1a (long s, char *set);

    /* extern char *strrpbrk (char *s, char *set); */
    #define  strrpbrk(s, set)                                strrpbrk1a ((long)set, s)
    extern char *strrpbrk1a (long s, char *set);

    /* extern char *strstr  (char *s, char *sub); */
    #define  strstr(s, sub)                                strstr1a ((long)sub, s)
    extern char *strstr1a (long s, char *sub);

    extern char *strtok  (char *str, const char *set);

    /* extern char *strtok_s  (char *str, const char *set, char **save_ptr); */
    #define  strtok_s(s, set, save_ptr)        (!(ACC^ACC) ? pploadlp ((long)s, (char**)save_ptr) : strtok_s1 (set))
    extern char *strtok_s1 (const char *set);

    extern char memcmp (void *s1, void *s2, int n);    // (void *R0R4R5, void *R1R2R3, int R6R7)
    extern void *memcpy (void *s1, void *s2, int n);   // (void *R0R4R5, void *R1R2R3, int R6R7); *s2-->*s1
    extern void *memchr (void *s, char val, int n);           // (void *R1R2R3, char R5, int R6R7)

    /* extern void *memccpy (void *s1, void *s2, char val, int n); */                   // *s2-->*s1
      #define  memccpy(dst, src, c, n)                (!(ACC^ACC) ? ploadcp (c, src) : memccpy1 (n, dst))
    extern void *memccpy1 (int n, void *dst);                                                                   // *s2-->*s1

    extern void *memmove (void *s1, void *s2, int n);  // (void *R0R4R5, void *R1R2R3, int R6R7); *s2-->*s1
    extern void *memset  (void *s, char val, int n);   // (void *R1R2R3, char R5, int R6R7)
    #pragma RESTORE

    #endif



    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 00:57
  • 签到天数: 148 天

    [LV.7]常住居民III

    39

    主题

    889

    回帖

    4154

    积分

    荣誉版主

    积分
    4154
    发表于 2024-3-24 02:44:37 | 显示全部楼层
    Keil C51当然是优秀的,好用的,但不是没有 BUG,至今我只找到 2个隐藏很深的 BUG !



    例如下面这个 Keil C51 库函数:


    $NOMOD51

    NAME     PSTPTR

    /**********************************************************************************************

    // 指针 类型, 堆栈内 通用指针 弹出后 写入 --> @(R1R2R3) 指向
                       // 入口堆栈: 返回地址 + 依次压入 R3R2R1

    *  用   途  :MCS51系列MCU
    *  作   者  :许意义
    *  版   本  :2.00
    *  日   期  :2024-2-1  

    **********************************************************************************************/


    ?PR?_PSTPTR?PSTPTR SEGMENT CODE   
            PUBLIC  ?C?PSTPTR
            EXTRN        CODE (?C?PSTXDATA)
            EXTRN        CODE (?C?PSTIDATA)
            EXTRN        CODE (?C?PSTPDATA)

    RSEG  ?PR?_PSTPTR?PSTPTR


    ?C?PSTPTR:                // 指针 类型, 堆栈内 通用指针, 弹出后 写入 R1R2R3
                                    CJNE     R3,#0x01,PSTPTR_1
                                    MOV      DPL,R1
                                    MOV      DPH,R2
                                    POP      B
                                    POP      ACC
                                    MOV      R0,A
                                    POP      ACC
                                    MOV      R1,A
                                    POP      ACC
                                    MOV      R2,A
                                    POP      ACC
                                    MOV      R3,A
                                    MOV      A,R0
                                    PUSH     ACC
                                    PUSH     B
                                    LJMP     ?C?PSTXDATA
    PSTPTR_1:                JNC      PSTPTR_2
                                    MOV      A,R1
                                    MOV      R0,A
                                    POP      DPH
                                    POP      DPL
                                    POP      ACC
                                    MOV      R1,A
                                    POP      ACC
                                    MOV      R2,A
                                    POP      ACC
                                    MOV      R3,A
                                    PUSH     DPL
                                    PUSH     DPH
                                    LJMP     ?C?PSTIDATA
    PSTPTR_2:                CJNE     R3,#0xFE,PSTPTR_3
                                    MOV      A,R1
                                    MOV      R0,A
                                    POP      DPH
                                    POP      DPL
                                    POP      ACC
                                    MOV      R1,A
                                    POP      ACC
                                    MOV      R2,A
                                    POP      ACC
                                    MOV      R3,A
                                    PUSH     DPL
                                    PUSH     DPH
                                    LJMP     ?C?PSTPDATA
    PSTPTR_3:                POP      DPH                          // 原 Keil C51 是错的!  未恢复压栈内指针
                                    POP      DPL                          // 现已修正!
                                    DEC             SP
                                    DEC             SP
                                    DEC             SP
                                    CLR             A
                                    JMP      @A+DPTR

                                    END

    点评

    平常我很少用库函数的,这个函数在哪个头文件?或由哪个库函数间接调用的?  发表于 2024-3-24 07:57
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 00:57
  • 签到天数: 148 天

    [LV.7]常住居民III

    39

    主题

    889

    回帖

    4154

    积分

    荣誉版主

    积分
    4154
    发表于 2024-3-24 03:35:08 | 显示全部楼层
    zxcv1973 发表于 2024-3-23 22:32
    总看杨老师在给别人出测试题,谁能给杨老师也出出测试题?

    本水贴, 没一点技术含量, 讨论了 N天, 得出一个傻子都会的结论, 使用万金油 关中断.

    我是没本事给 X老师出测试题.



    既然大家讨论的这么热烈, 我不出点有些难度的题, 对不起大家了.


    这里的大虾都是 OS专家, 我就出个 OS方面的题吧 !


    记得 X老师说过: 关了 中断EA, OS就不能工作了.


    也有网友说过: 中断是 OS的灵魂, 关闭 EA, OS魂都没了, 还能干啥?


    我这道题就是反向思维, 写(或移植)个 OS系统, 离开 EA, 即无论用户何时何地关中断, 都不能影响 OS系统的运行.


    欢迎大家参与讨论, 来点真正的干货, 让 STC论坛, 拥有足够的含金量, 别老喝水, 不嫌肚子涨吗?

    点评

    LAOXU,你好,你在这楼出的题目我已经解决了,我的答案已经放在 《许出题我来答:写(或移植)个 OS系统, 无论何时何地关中断, 都不能影响 OS系统的运行》(https://www.stcaimcu.com/forum.php?mod=viewthread&tid=741  详情 回复 发表于 2024-3-24 12:40
    你好,我新开了一个贴来回答你的这个问题,你在这楼出的题目我已复制到 《许出题我来答:写(或移植)个 OS系统, 无论何时何地关中断, 都不能影响 OS系统的运行》(https://www.stcaimcu.com/forum.php?mod=viewthrea  详情 回复 发表于 2024-3-24 12:21
    武林之所以精彩,就是因为有华山论剑! LAOXU这次题目出得好,使大家有了一个交流的机会。 这次我不太厚道,把你出的题目反考回你,这里给你说抱歉了。 这次你69楼出得题目非常好,我愿意回答。 LAOXU,以后我  详情 回复 发表于 2024-3-24 11:26
    问:关了中断EA, OS就不能工作了. 答:目前本坛三个常见的RTOS "FreeRTOS, uCOS, CosyOS" 都依赖中断切换任务。 其中FreeRTOS or STC32G12K128 官方简洁可靠版V1.0.2 ,是基于时钟滴答切换任务。 问:中断是 OS的  详情 回复 发表于 2024-3-24 08:34
    1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 00:57
  • 签到天数: 148 天

    [LV.7]常住居民III

    39

    主题

    889

    回帖

    4154

    积分

    荣誉版主

    积分
    4154
    发表于 2024-3-24 06:58:00 | 显示全部楼层
    CosyOS 发表于 2024-3-23 23:46
    有疑虑的朋友自己反汇编看下吧

    你好 !
    有一个问题, 一直想和你核实,
    你在 CosyOS中, PendSV_Handler 使用INT0中断,是否意味着用户不能使用 P32(INT0), 作为通用 I/O口了.  

    点评

    是的。 所以该功能可配置,用户应选择一个不使用的硬件中断,对应的端口也不能使用。 另外对该中断还有要求: 1、必须支持置标志位触发,而不是IO口电平触发; 2、在关闭该中断的前提下,置标志位后再开启该中断,可  详情 回复 发表于 2024-3-24 12:01
    回复 支持 反对 送花

    使用道具 举报

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

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-5-20 01:22 , Processed in 0.069417 second(s), 67 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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