8051: function pointer 與 data overlaying

在嵌入式系統中,利用 struct + function pointer 來做 OOP, 一直是常見的設計手法。如:
typedef struct
{
   int  (*read)(void* buf, uint32_t buf_size, uint32_t count);
   int  (*write)(void* buf, uint32_t buf_size, uint32_t count);
   void (*process)();
} device_t;

但是最近我在 8051 上這樣寫卻遇到了問題:
u8 data i;
for (i = 0; i < total_dev; ++i)
{
    g_dev[i]->process();
}

在上面的程式中我發現變數i 會在呼叫函式後被修改而跳過某些值,更深入追進去函式後發現函式裡面有個區域變數和變數i 是配置在相同的位址上!

為什麼會這樣呢? 一般的 C compiler 會將區域變數(local variable)配置 stack 中,但是傳統 8051 stack 的上限為 256 bytes,因為 8051 stack pointer 只能存取內部記憶體區。為了保留多一點空間給 stack 使用以及效率上的考量,Keil C51 會將 local variable 配置在一個固定的位址上,配合函式相依性(call dependency)的分析來確保函式的區域變數不會互相干擾。

在 Keil C 中把這個技術稱為 data overlaying,屬於 optimization level 2。基本上這是一定會使用到的最佳化技術。我的解決方式是避免在 8051 中使用 function pointer 的寫法,因為這樣會讓 compiler 無法正確分析函式相依性而導致無法預期的執行結果。

Reference:


0 意見 :: 8051: function pointer 與 data overlaying

張貼留言