在MDK中使用$Sub$$和$Super$$的记录
在MDK开发环境下,对于某些无法被更改的函数,我们需要更改这些函数执行前后的逻辑,偏偏又无法更改到调用这些函数并已经被封装的代码,这真是让人一筹莫展。
幸好MDK给我们留了一个后门,让我们充分使用“$Sub$$”和“$Super$$”来完成这个目标。
比如某个函数
extern void foo(void);
我们要在它执行的前后进行一段特定的处理,那么参考下面的代码:
/*定义 foo 函数*/ void foo(void) { printf("f()\n"); } /*定义foo的补丁函数*/ void $Sub$$foo(void) { /*需要在 foo() 之前执行的代码块*/ printf("before_foo()\n"); /*调用 foo(),要注意使用前缀"$Super$$"*/ $Super$$foo(); /*需要在 foo() 之后执行的代码块*/ printf("execute_after_f()\n"); } /* 疑问:我定义 printf 的补丁函数 $Sub$$printf, 实际调用 printf 的时候,并没有进入 $Sub$$printf, 这是为何? */ int $Sub$$printf(const char *fmt, ...) { $Super$$printf("<*> "); return $Super$$printf(fmt); } int main(void) { uint32_t limitedTick; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); tick_initialize(); trace_initialize(user_command_deal); printf("\n execute \"foo();\" result:\n\n"); /* 直接写作"foo();",理论上应该看到 <*> before_foo(), <*> f(), <*> after_foo() 三行日志,实际上前面的“<*>”没有输出。 也就是说,printf函数的补丁没生效,foo的补丁生效了。 为什么呢? */ foo(); /*采用 $Sub$$printf 的形式去调用的话就失去意义了。*/ $Sub$$printf("i am printed by \"$Sub$$printf\".\n"); while(1); return 0; }
注意:
1、必须定义一个新的以“$Sub$$”作为前缀,后面紧跟“欲被处理的函数名”的函数,例如 “$Sub$$foo()”.
2、在补丁函数里面需要以 “$Super$$foo()” 的方式去调用原始的 foo 函数,而不应该直接写作 “foo()”去调用。
(不要“$Super$$”前缀也能调用到,不建议这么做。感觉要是不加前缀,就好像进入无限嵌套一样的,不断的调用自己。)
3、这个特性仅在ARM CC编译器内被支持,所以一般都会使用宏“#if defined(__CC_ARM)”来囊括处理。
4、既然是针对 foo 的补丁,在调用的地方自然就应该写作 "foo();",而不是 "$Sub$$foo();",要不然补丁有何意义呢?
疑问:
为什么我针对printf的补丁不生效呢?
经过调试,发现printf被替换成了 __2printf,如果针对 printf 这个“词”进行 $Sub$$ 前缀化,是达不到目标的,改成 $Sub$$__2printf 之后,再使用 printf 的时候就实际执行了 $Sub$$__2printf 。
搞不懂为什么 printf 会变成 __2printf。
参考:
https://www.cnblogs.com/raswin/p/10031117.html
https://blog.csdn.net/qq_42860728/article/details/89495882