【问题标题】:Can you programmatically detect the size in bytes of a function in C [duplicate]您能否以编程方式检测 C 中函数的字节大小 [重复]
【发布时间】:2018-06-30 06:10:56
【问题描述】:

我正在为嵌入式系统编写代码,在这种系统中,将代码从 ROM 复制到 SOC 的内部存储器然后执行它会更有效。有没有办法以编程方式获取函数的字节大小,以便我可以使用像 memcpy 这样的函数将函数的指令复制到内部存储器。

有没有更好的方法来做到这一点?

【问题讨论】:

  • 你用的是什么工具链? ROM有多大? RAM 有多大?
  • 你可以得到一个函数的地址,然后如果你计算两个相邻函数的地址之间的差异,你可能会得到第一个函数的大小。我不确定,只是一个想法。
  • 是的,这是可能的。你可以考虑使用 sizeof() 函数。
  • @LethalProgrammer sizeof() 返回数据类型的大小。因此 sizeof(function) 将返回指向所述函数的指针的大小,而不是实际函数在内存中的大小。
  • 这听起来很可疑。这意味着功能代码与位置无关或可重定位。另外,如果它调用了一些东西怎么办?

标签: c embedded


【解决方案1】:

有没有更好的方法来做到这一点?

很可能是这样,我真的希望其他人的回答可以提供更简单的方法,但现在我将详细介绍您建议的方法。

如果程序以 ELF 格式编译(我不知道其他格式),您的所有函数都将包含在 ELF 文件的 .text 部分中。您可以使用符号表在文本部分中找到此功能。要获取此函数的大小,您也许可以使用 Elf64_Sym 或 Elf32_Sym 结构的 st_size 成员,但我不完全确定它会给出正确的大小。你可以做的(有点hacky,诚然)是遍历其他符号,并立即找到它之后的那个,然后减去以获得大小。当然,您必须牢记对齐规则,但这不是什么大问题 - 如果您复制额外的字节,它们无论如何都不会被执行。

另外请记住,某些代码是在对其在内存中的偏移量进行某些假设的情况下编译的。如果您将函数直接复制到内存中,您可能需要手动修补 GOT 和/或 PLT。知道您可能应该为 位置无关代码 编译您想要包含的函数 -PIC 和 -fPIC,至少在 GCC 中是这样。

如果您需要有关如何访问符号表或 ELF 的文本部分的更多详细信息,我可以添加更多详细信息。

【讨论】:

  • 这一切听起来都是噩梦。如果它调用别的东西怎么办?
  • OP 只询问如何获取函数大小 - 所以这是我详细介绍的唯一部分。如果它调用其他东西,OP 将需要自己处理这些符号。我之前写过一个动态加载器,并且有符号重定位和修补 PLT 和 GOT 的经验,所以如果 OP 要求,我可以明确解释这些。对于高级概述 - OP 应该将他的源代码编译为 PIC,memcpy 所有必需的函数代码,然后将使用的任何外部库添加到 .dynamic 部分,以便动态加载器在运行时处理这些库。
【解决方案2】:

使用某些编译器,您可以通过计算函数地址与紧随第一个函数的另一个函数的地址之间的差异来获得函数大小。

但这真的取决于编译器。以 Visual C++ 为例,这两个函数都必须是 static 函数。使用 GCC,如果优化 O2 或更高版本被激活,它将不再起作用。

即使您设法将您的函数复制到内存中的其他位置,您也可能无法使用它,特别是如果它引用其他函数,或者如果它引用全局/静态变量,或者如果代码不是位置独立的,等等

所以这是一个简单的解决方案,它可能适用于您的情况,但不能被视为通用解决方案

下面是一个使用 gcc 和 Visual C++ 的示例,在 Windows 10 和 WSL 上进行了测试(不要使用 gcc 激活优化)。

#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef __linux
#include <sys/mman.h>
#endif

// The function to copy
static int fib(int m)
{
    int v1 = 0, v2 = 1, n;

    if (m == 0) return 0;
    for (n = 1; n < m; n++)
    {
        int v = v1 + v2;
        v1 = v2;
        v2 = v;
    }
    return v2;
}

static void endFib(void)
{
    // This function follow immediatly the fib function
    // and it exists only to get its address and compute the size of fib function
}

int main(int argc, char *argv)
{
    long sizeFib;
    int (*copyFib)(int);

    printf("&fib=%p\n", (char *)fib);
    sizeFib = (char *)endFib - (char *)fib;
    printf("size of fib : %ld\n", sizeFib);

    printf("fib(8) : %d\n", fib(8));

    // For the example the allocated copy must be in an executable part of the memory.
#ifdef _WIN32
    copyFib = VirtualAlloc(NULL, sizeFib, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#endif
#ifdef __linux
    copyFib = mmap(NULL, sizeFib, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
#endif
    memcpy(copyFib, fib, sizeFib);
    printf("&copyFib=%p\n", copyFib);
    printf("copyFib(8) : %d\n", copyFib(8));

    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-03
    • 2016-08-23
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 2014-12-27
    • 2014-03-07
    • 1970-01-01
    相关资源
    最近更新 更多