是否有任何非奇特的架构/ OS /编译器改变:
void func(void *, int, int)
为:
int func(void *, int, int)
会打破ABI吗? (即,使用“int”版本运行时,为“void”版本的共享库编译的程序会中断)
答案 0 :(得分:8)
有几条评论说没有,我们可以通过一点推理加强这一点。在最熟悉的ABI中,允许使用带有声明void func(void *, int, int)
的函数来使用寄存器,其中int
结果将作为临时寄存器返回;它不需要保存和恢复它。声明为int func(void *, int, int)
的函数必需,以使用将返回int
结果的寄存器。在其他方面,这些声明是相同的。因此,int func(void *, int, int)
的任何实现的机器代码也是满足void func(void *, int, int)
的机器代码。
换句话说,调用者无法区分故意在返回寄存器中返回结果的机器代码,这些代码恰好会在该寄存器中留下一些临时计算。
请注意,这种推理要求被调用函数隐藏在ABI后面;它依赖于ABI指定的二进制行为。如果在编译被调用函数时(或者可能影响调用实现方式的实现的其他部分)可以看到被调用函数的源,那么优化可能导致绕过ABI的行为(例如,观察被调用的例程)不使用返回寄存器,因此在调用者中使用它来保持一些预期在调用中保持不变的值。)
由于您说这是针对共享库的,因此您可能很安全:共享库是单独编译的,其源不可供其调用者使用。但是,您应该考虑辅助渠道。例如,共享库可能是共享源并包含跨库调用的一组库的一部分。在这种情况下,某人可能拥有旧版本的共享库,该库使用void
源的视图和包含int
源的共享库的新版本进行编译。 (甚至这需要不寻常的源代码安排或花哨的编译器,它们将信息集成到多个编译单元中。)