1. 程式人生 > 實用技巧 >在MDK中使用$Sub$$和$Super$$的記錄

在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的補丁不生效呢?

參考:

https://developer.arm.com/documentation/dui0377/g/accessing-and-managing-symbols-with-armlink/use-of--super---and--sub---to-patch-symbol-definitions

https://www.cnblogs.com/raswin/p/10031117.html

https://blog.csdn.net/qq_42860728/article/details/89495882