0

組み込みハードウェアでランタイム スタック分析を実行して、十分なスタック スペースが割り当てられていることを確認する必要があります。基本的な理論は理解できました。起動時に、スタックを既知のパターン (すべて 0xFF または 0xAA など) で初期化し、プログラムを実行できるようにします。実行すると、スタックは拡大および縮小しますが、元のパターンを復元することはありません。十分な時間が経過したら、スタックを調べて、最後に変更されたスタック値のアドレスを見つけます。

ポータブル ソリューションは必要ありません。dsPIC33EP512MU810 と PIC32MX795F512 用のソリューションだけが必要です。私のフォールバック計画は、スタックオーバーフローが発生するまでスタック サイズを段階的に減らすことですが、それはリリース候補ができて初めて機能します。

4

3 に答える 3

1

これは、XC16 コンパイラで dsPIC33EP512MU810 に使用したコードです。自動変数を作成することで、スタックの最上部近くにアクセスし、数バイト ( STACK_VAR_PAD) をインクリメントして、残りのスタックをガード バイトで埋めます。

#define STACK_VAR_PAD           0x0020
#define TOP_OF_STACK_ADDR       0x4000
#define STACK_GUARD_BYTE        0xEE

void WriteStackGuardBytes(void)
{
    static __eds__ char * ptr;
    static unsigned int start_addr;
    static unsigned int addr;

    //Use a variable on the stack
    char stack_var;

    ptr = &stack_var;
    //Casting to 32-bit first supresses complier warning
    //This chip uses a 16-bit address space
    start_addr = (unsigned long int)ptr + STACK_VAR_PAD;

    for (addr = start_addr; addr < TOP_OF_STACK_ADDR; addr++)
    {
        *((unsigned int *)(addr)) = STACK_GUARD_BYTE;
    }
}

unsigned int ReadStackGuardBytes(void)
{
    static __eds__ char * ptr;
    static unsigned int start_addr;
    static unsigned int addr;
    static unsigned int top_addr;

    //Use a variable on the stack here
    char stack_var;

    ptr = &stack_var;
    //Casting to 32-bit first supresses complier warning
    //This chip uses a 16-bit address space
    start_addr = (unsigned long int)ptr;
    top_addr = start_addr;

    for (addr = start_addr; addr < TOP_OF_STACK_ADDR; addr++)
    {
        if (*((unsigned int *)(addr)) != STACK_GUARD_BYTE)
        {
            top_addr = addr;
        }
    }

    return TOP_OF_STACK_ADDR - top_addr;
}

リンカは、スタックが で停止すると主張します0x8000(マップ ファイルを生成するように設定しました) が、それまではゼロが表示され0x4000、それ以降はガベージ データが表示されます。スタックの内容が未定であることは十分に理解していますが、この方法では、スタックがそれ以上に大きくなることはないと判断した0x1500ため、チェックするだけで0x4000機能します。

于 2013-11-18T16:23:15.247 に答える
0

ご存じのとおり、スタック オーバーフローを待つことは、考えられる最悪の解決策です。オーバーフローは、何もしない (!)、数値の符号を反転する、ロジック フローを変更する、前の金曜日に雨が降った火曜日にのみこれらすべてを実行するなど、あらゆる動作を引き起こす可能性があります。それはすべてランダムであり、それがあなたに起こったかどうかを知る方法はありません.

OS はありますか (単純なものでも)? その場合、優先度の低いタスクを作成して、他のタスクのスタックのガード バイト (既知のパターン) を監視し、それらが期待値に達していない場合に何かを実行させることができます。

OS がない場合は、動的分析ではなく静的分析に移行します。リンカー出力から最悪の場合の深さに関する有用な情報を消去できるはずです。これにより、各呼び出しのスタック使用量が得られ、呼び出しの依存関係グラフがわかります。関数呼び出しの上にスタックされた割り込みはカウントされないため、すべてを教えてくれるわけではありませんが、非常に近くなるはずです。最悪の場合の番号を取り、最悪の場合の割り込み番号を追加してから、念のためにとにかくパディングします...

于 2013-11-04T15:17:10.497 に答える