杨为民
发表于 2024-3-23 23:44:56
CosyOS 发表于 2024-3-23 23:26
首先声明:我所说的方法仅适用于本次讨论的题目,如果换一个题目可能根本就不行了,
具有很强的针对性。
“memcpy当然是可重入的了”,怎么证明?可否将反汇编的分析分享给大家
CosyOS
发表于 2024-3-23 23:45:49
杨为民 发表于 2024-3-23 23:39
你觉得“memcpy”函数是可重入的或者是不可重入的?
“memcpy”函数如果是不可重入的,那就没有解决问题
CosyOS
发表于 2024-3-23 23:46:41
杨为民 发表于 2024-3-23 23:44
“memcpy当然是可重入的了”,怎么证明?可否将反汇编的分析分享给大家
有疑虑的朋友自己反汇编看下吧
杨为民
发表于 2024-3-23 23:52:04
CosyOS 发表于 2024-3-23 23:45
这个证明好!这是C51的标准库函数,LAOXU白忙活了,LAOXU老师的全称否定也被打破了。
LAOXU
发表于 2024-3-24 01:47:08
CosyOS 发表于 2024-3-23 23:26
首先声明:我所说的方法仅适用于本次讨论的题目,如果换一个题目可能根本就不行了,
具有很强的针对性。
我随手例了一个不可重入函数的例子, 你改换成其他可重入函数. 当然没事了
这跟我将 strncpy 函数, 改写成可重入函数. 其实是一回事, 对吗?
LAOXU
发表于 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
LAOXU
发表于 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 intiloadcp (char c, char *s);
extern char cloadcp (char c, char *s);
extern char *ploadp (char *s);
extern intiloadp (char *s);
extern char cloadp (char *s);
/* extern char *strcat (char *s1, char *s2); */
#definestrcat(dst, src) strcat1a ((long)src, dst)
extern char *strcat1a (long dst, char *src);
/* extern char *strncat (char *s1, char *s2, int n); */
#definestrncat(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); */
#definestrncmp(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); */
#definestrncpy(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); */
#definestrspn(s, set) strspn1a ((long)s, set)
extern int strspn1a (long s, char *set);
/* extern int strcspn (char *s, char *set); */
#definestrcspn(s, set) strcspn1a ((long)s, set)
extern int strcspn1a (long s, char *set);
/* extern char *strpbrk (char *s, char *set); */
#definestrpbrk(s, set) strpbrk1a ((long)s, set)
extern char *strpbrk1a (long s, char *set);
/* extern char *strrpbrk (char *s, char *set); */
#definestrrpbrk(s, set) strrpbrk1a ((long)set, s)
extern char *strrpbrk1a (long s, char *set);
/* extern char *strstr(char *s, char *sub); */
#definestrstr(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); */
#definestrtok_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
#definememccpy(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
LAOXU
发表于 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
LAOXU
发表于 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
发表于 2024-3-24 06:58:00
CosyOS 发表于 2024-3-23 23:46
有疑虑的朋友自己反汇编看下吧
你好 !
有一个问题, 一直想和你核实,
你在 CosyOS中, PendSV_Handler 使用INT0中断,是否意味着用户不能使用 P32(INT0), 作为通用 I/O口了.
页:
1
2
3
4
5
6
[7]
8
9
10