我正在尝试将历史功能语言解释器(EMAS 的 KRC)移植到现代系统(Unix 的 C),它有一个垃圾收集器,希望能够扫描堆栈以查找指向堆的指针,以了解它必须重新定位哪些指针在 GC 期间移动堆中的对象时。为此,必须在堆栈中找到所有指向堆的函数参数和局部变量。
现在,有一段时间,“register”关键字的意思是“如果你愿意,你可以把这个变量放在寄存器中”,否则它就在堆栈上,但现在所有(GCC、Clang、Tinyc/tcc)C 编译器似乎无论如何都将局部变量放入寄存器中,无法禁用此行为,结果是 GC 丢失了一些属于正在进行的函数的值,未能保存它们并破坏了堆。
有没有办法告诉任何这些编译器使用原始的 C 语义,除非你说“注册”,否则所有局部变量都在堆栈上?
我有一些棘手的“解决方案”:
- 在任何地方添加额外的代码来获取每个面向堆的局部变量的地址并将其传递给一个虚拟函数,作为强制它位于内存位置的一种方式;
- 使所有静态函数全局化,以避免函数内联和由此产生的内联函数参数的优化;
- 将所有机器寄存器压入堆栈的存根将 GC() 函数括起来,调用真正的 GC() 函数,然后将它们弹出;
这一切似乎都改善了问题,但非常老套且不可靠。
有没有更好的方法来实现所需的结果,确保所有函数参数和局部变量都在堆栈上?