以下代码没有按预期工作,但希望能说明我的尝试:
long foo (int a, int b) {
return a + b;
}
void call_foo_from_stack (void) {
/* reserve space on the stack to store foo's code */
char code[sizeof(*foo)];
/* have a pointer to the beginning of the code */
long (*fooptr)(int, int) = (long (*)(int, int)) code;
/* copy foo's code to the stack */
memcpy(code, foo, sizeof(*foo));
/* execute foo from the stack */
fooptr(3, 5);
}
显然,sizeof(*foo)
不会返回 foo()
函数的代码大小。
我知道执行堆栈在某些 CPU 上受到限制(或者至少如果设置了限制标志)。除了 GCC 的嵌套函数最终可以存储在堆栈上之外,在标准 C 中有没有办法做到这一点?
最佳答案
这种事情的一个有效用例是一个嵌入式系统,它通常会用完闪存,但需要能够在现场重新编程。为此,部分代码必须从其他存储设备运行(在我的例子中,FLASH 设备本身无法删除和编程一页,同时允许从任何其他页面读取,但有些设备可以做到这一点),并且系统中有足够的 RAM 来容纳闪存写入器和要写入的新应用程序镜像。
我们用 C 编写了必要的 FLASH 编程函数,但使用 #pragma
指令将其放置在与其余代码不同的 .text
段中。在链接器控制文件中,我们让链接器为该段的开始和结束定义全局符号,并将其定位在 RAM 中的基地址,同时将生成的代码与位于 FLASH 中的加载区一起放置.data
段和纯只读.rodata
段的初始化数据; FLASH中的基地址也被计算并定义为全局符号。
在运行时,当应用程序更新功能被执行时,我们将新的应用程序图像读入其缓冲区(并进行了所有应该进行的健全性检查以确保它实际上是该设备的应用程序图像)。然后我们将更新内核从它在 FLASH 中的休眠位置复制到它在 RAM 中的链接位置(使用链接器定义的全局符号),然后像调用任何其他函数一样调用它。我们不必在调用点做任何特殊的事情(甚至不需要函数指针),因为就链接器而言,它一直位于 RAM 中。事实上,在正常操作期间,特定的 RAM 具有非常不同的用途,这对链接器来说并不重要。
也就是说,所有使这成为可能的机制要么超出了标准的范围,要么完全实现了定义的行为。该标准不关心代码在执行之前如何加载到内存中。它只是说系统可以执行代码。
关于c - 是否可以从标准 C 中的堆栈执行代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3755491/