我正在为一个嵌入式系统编写代码,它更有效地将代码从ROM复制到SOC的内部内存,然后执行它。有没有办法以编程方式获取函数的大小(以字节为单位),以便我可以使用像memcpy这样的函数将函数的指令复制到内部内存中。
有更好的方法吗?
发布于 2018-06-30 07:00:56
有更好的方法吗?
很可能是这样,我真的希望其他人能给出一个更简单的解决方案,但是现在我将详细介绍一下您建议的方法。
如果程序是以ELF格式编译的(我不知道其他格式),那么所有函数都将包含在ELF文件的.text部分。您可以使用符号表在文本部分找到此函数。要获得此函数的大小,您可能可以使用st_size成员的Elf64_Sym或Elf32_Sym结构,但我不完全确定这将给出正确的大小。你能做的(无可否认,有点烦躁)是迭代其他符号,并在它之后立即找到一个,并减去得到的大小。当然,您必须记住对齐规则,但这并不是太大的问题--如果您复制额外的字节,它们无论如何都不会被执行。
还请记住,有些代码是在对内存中的偏移量进行某些假设的情况下编译的。如果将函数直接复制到内存中,则可能需要手动修补GOT和/或PLT。知道您可能应该编译-PIC和-fPIC中包含的函数,用于位置独立代码,至少在GCC中是这样的。
如果您需要更多关于如何访问符号表或ELF的文本部分的详细信息,我可以添加更多详细信息。
发布于 2018-06-30 12:34:44
使用一些编译器,您可以通过计算函数的地址与直接跟随第一个函数的另一个函数的地址之间的差异来获得函数大小。
但它确实取决于编译器。例如,对于VisualC++,这两个函数都必须是static函数。对于GCC来说,如果激活优化O2或更好的话,它就不再起作用了。
即使您设法将函数复制到内存中的其他地方,您也可能无法使用它,特别是如果它引用其他函数,或者引用全局/静态变量,或者如果代码不是位置无关的,等等。
因此,这是一个简单的解决方案,在您的情况下可能有效,,但不能认为它是一个通用的解决方案。
下面是一个在windows 10和WSL上测试的gcc和visual C++的例子(不要用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("©Fib=%p\n", copyFib);
printf("copyFib(8) : %d\n", copyFib(8));
return 0;
}https://stackoverflow.com/questions/51112238
复制相似问题