2

基本上,我试图找到一种可靠的方法来获取 C 函数的字节长度。

一些人建议使用函数的地址和紧随其后的另一个函数的地址。我不想使用这种方法,因为我不相信它是可靠的。编译器可以移动东西,它看起来有点hack-ish。

我想出的解决方案是在函数的开头和结尾使用两个标签。我已经声明了标签:

__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 实现可以内联一个函数。它可能在某些地方内联该功能,并在另一个地方提供非内联版本。该函数可能在其入口点之前有代码。该函数可能在其退出点之后有代码。一个函数可能有多个退出点。调用的其他例程可能内联在函数内。该函数可能与其他函数共享代码(例如,两个函数做同样的事情,除了一个函数在开始之前对其参数执行一些轻微的操作,可能会被赋予两个独立的入口点,这些入口点主要是通用代码)。一个函数可能在一个地方有一些代码,在另一个地方有其他代码,中间还有其他函数的代码。一个函数,即使由编译器编写为单个代码序列,也可能被链接器分解为块并重新排列。

如果您希望在上述情况下坚持下去,您可以尝试:

#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 回答