2

基本的に、C 関数の長さをバイト単位で取得する信頼できる方法を見つけようとしています。

関数のアドレスと、それに続く別の関数のアドレスを使用することを提案する人もいます。信頼できるとは思えないため、この方法は使用したくありません。コンパイラは物事を動かすことができますが、それは少しハックっぽいようです.

私が思いついた解決策は、関数の最初と最後に 2 つのラベルを使用することです。次のラベルを宣言しました。

__asm__ __volatile__("func_start/end:");

さて、私の問題は、これらのラベルのアドレスを C の変数に戻すのに問題があることです。

ここに私がすでに試したいくつかのコードがあります:

unsigned int  addr, len;

__asm__ __volatile__("mov  $func_start, %[address]\n\t"\
                    "mov  $func_end, %[length]\n\t"\
                    : [address]"=r"(addr), [length]"=r"(len));


__asm__ __volatile__("mov  %0, $func_start \n\t"\
                     "mov  %1, $func_end\n\t"\
                    : "=r"(addr), "=r"(len));

これらの例は両方とも、コンパイル中に「ARM register expected」というエラーを出します。私は ARM アセンブリ (x86 は言うまでもなく) の経験があまりないので、何が問題なのかわかりません。次の x86 コードを ARM に移植しようとしました。

__asm__ __volatile__("movl  $enc_start, %0\n\t"\
                    "movl  $enc_end, %1\n\t"\
                    : "=r"(addr), "=r"(len));

私は明らかにここで何か間違ったことをしています。誰かが私が間違っていることを説明できれば幸いです。私はこれで数週間立ち往生しています。ありがとう!

4

1 に答える 1

4

関数の長さには明確な意味が定義されていないため、関数の長さを取得する信頼できる方法はありません。

AC 実装は、関数をインライン化する場合があります。一部の場所で関数をインライン化することも、別の場所でインライン化されていないバージョンを提供することもできます。関数のエントリ ポイントの前にコードがある場合があります。関数には、その出口点の後にコードがある場合があります。関数には複数の出口点がある場合があります。呼び出される他のルーチンは、関数内でインライン化される場合があります。関数は、他の関数とコードを共有する場合があります (たとえば、開始前にパラメーターに対してわずかな操作を実行することを除いて同じことを行う 2 つの関数には、ほとんど共通のコードへの 2 つの別個のエントリ ポイントが与えられる場合があります)。関数には、ある場所にコードがあり、別の場所に別のコードがあり、その間に他の関数のコードがある場合があります。関数は、コンパイラによって単一のコード シーケンスとして記述された場合でも、リンカーによってブロックに分割され、再配置される場合があります。

上記にもかかわらず持続したい場合は、次のことを試してください。

#include <stdio.h>


static void foo(void)
{
    __asm__ __volatile__("_foo_start:");
    printf("Hello, world.\n");
    __asm__ __volatile__("_foo_end:");
}


int main(void)
{
    extern const char foo_start[], foo_end[];
    printf("Difference = 0x%tx.\n", foo_end - foo_start);
    foo();
    return 0;
}

もちろん、C 標準ではサポートされていません。

于 2013-06-25T19:36:42.810 に答える