6

金属にライブラリ(マスクROM)が組み込まれている独自のMCUを使用しています。私が使用しているコンパイラはclangで、GCCのようなインラインASMを使用しています。私が直面している問題は、ライブラリに一貫した呼び出し規約がないため、ライブラリを呼び出すことです。解決策を見つけましたが、場合によっては、コンパイラーが呼び出しの直前にclobberが登録する最適化を行うことがわかりましたが、私が行っている方法に何か問題があると思います。これが私が使用しているコードです:

int EchoByte()
{
    register int asmHex __asm__ ("R1") = Hex;
    asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
            :
            :"r"(asmHex)
            :"%R1");
    ((volatile void (*)(void))(MASKROM_EchoByte))(); //MASKROM_EchoByte is a 16-bit integer with the memory location of the function
}

これには明らかな問題があります。変数「asmHex」がレジスタR1にアサートされている間、実際の呼び出しはそれを使用しないため、コンパイラは呼び出し時にR1が予約されていることを「認識しません」。このケースを排除するために、次のコードを使用しました。

int EchoByte()
{
    register int asmHex __asm__ ("R1") = Hex;
    asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
            :
            :"r"(asmHex)
            :"%R1");
    ((volatile void (*)(void))(MASKROM_EchoByte))();
    asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
            :
            :"r"(asmHex)
            :"%R1");
}

これは私には本当に醜いようで、もっと良い方法があるはずです。また、呼び出し自体にはasmHex変数が必要であることを示さないため、コンパイラーがその間にナンセンスを実行する可能性があるのではないかと心配しています。残念ながら、((volatile void(*)(int))(MASKROM_EchoByte))(asmHex)は、引数をR2 +に入れるC規則に従うため、機能しません(R1はスクラッチ用に予約されています)

残念ながら、マスクROMライブラリを変更することは不可能であり、頻繁に使用されるルーチンが多すぎて、すべてをC /C++で再作成できないことに注意してください。

乾杯、そしてありがとう。

編集:ASMブロックで関数を呼び出すことはできますが、コンパイラには呼び出しのない関数が最適化されており、アセンブリで呼び出すと呼び出しがないように見えることに注意してください。インラインASMに関数呼び出しが含まれていることを示す方法があれば、このルートに進むことができますが、そうでない場合は、リターンアドレスが壊れる可能性があります。いずれにせよ、これを行う方法を見つけることができませんでした。

4

1 に答える 1

2

上記のコメントによると:

最も一般的な答えは、.s単に奇抜な呼び出しを実行するスタブ関数を(ファイル内の)アセンブリに実装する必要があるということです。ARMでは、これは次のようになります

// void EchoByte(int hex);

_EchoByte:
    push {lr}
    mov  r1, r0       // move our first parameter into r1
    bl   _MASKROM_EchoByte
    pop  pc

マスクROMルーチンごとにこれらのスタブの1つを実装すれば、完了です。

あれは何でしょう?500個のマスクROMルーチンがあり、それほど多くのコードをカットアンドペーストしたくないですか?次に、間接参照のレベルを追加します。

// typedef void MASKROM_Routine(int r1, ...);
// void GeneralPurposeStub(MASKROM_Routine *f, int arg, ...);

_GeneralPurposeStub:
    bx   r0

構文を使用してこのスタブを呼び出しますGeneralPurposeStub(&MASKROM_EchoByte, hex)。のパラメータを期待するすべてのマスクROMエントリポイントで機能しますr1本当に風変わりなエントリポイントには、独自の手書きのアセンブリスタブが必要です。

しかし、本当に、本当に、本当に、C関数のインラインアセンブリを介してこれを行う必要がある場合は、(@ JasonDが指摘したように)必要なのは、リンクレジスタlrをクローバーリストに追加することだけです。

void EchoByte(int hex)
{
    register int r1 asm("r1") = hex;
    asm volatile(
        "bl  _MASKROM_EchoByte"
        :
        : "r"(r1)
        : "r1", "lr"   // Compare the codegen with and without this "lr"!
    );
}
于 2013-06-19T00:10:48.970 に答える