使用C中的函数指针重新启动计算机

当我遇到一个在执行时重新启动计算机的程序时,我正在学习C语言中的函数指针。

void (*f) (void); f=(void (*)(void) MK_FP(0xFFFF,0x0000); f(); 

(void(*)(void))部分不在提供的原始文本中,我不得不进行此添加以获取要编译的代码。 这是如何运作的?

非常感谢你。

关于从数字文字手动构造函数指针并调用它们的程序,C标准仅表示行为未定义 。 这意味着您不能指望程序在计算机之间的行为方式相同,甚至从运行到同一台计算机上运行。

关于这个特定的程序,我们可以做出有根据的猜测,它应该做什么,在什么情况下它会实际做到这一点:

原始IBM PC的原始操作系统(通常称为MS-DOS)在加电时开始在分段地址FFFF:0000处执行代码。 (有些消息来源说F000:FFF0代替 – 因为进入这里太繁琐的原因,这是相同的物理地址 ,但表达了不同的方式,并且可能表现不同,具体取决于该位置的代码。)因为这个操作系统是如此裸机,在机器启动并运行后跳转到该位置将执行热重启的近似值。

假设您的MK_FP宏从段和偏移值构造分段函数指针,那么, 当您的程序在运行MS-DOS的IBM PC上执行时 ,它会跳转到FFFF:0000并执行热重启的近似值。

在更现代的操作系统(包括IBM PC后代的所有当前操作系统)上,此程序保证不会重新启动计算机,因为不允许非特权用户模式程序重新启动计算机。 此外, MK_FP()操作本身在现代32位或64位用户模式程序中没有意义,因为它们在平坦的地址空间中运行。 代码可以编译,但它几乎肯定会调用一个没有映射到它的内存的地址,所以我希望程序崩溃。 但其余的操作系统将继续保持运行状态。 如果您在DOS模拟器中运行程序,它可能会重新启动模拟器 ,但同样,操作系统的其余部分将继续运行。

可以编写一个重新启动现代操作系统的程序 – 事实上,你的计算机上已经至少有一个这样的程序,或者你没有办法在没有物理电源开关的情况下重启它! – 但它必须很好地询问内核,使用特殊的系统调用(Unix系列: reboot(2) ; Windows: ExitWindowsEx ),它必须以特殊权限运行,否则调用将失败。

也就是说,跳转到FFFF:0000加上一堆辅助鸡挥手当前版本的Linux可能用于触发基于x86的计算机重启的低级操作之一。 只有在其他一些事情失败的情况下才会尝试,但它就在那里。 有关整个过程的概述,请参见http://lxr.free-electrons.com/source/arch/x86/kernel/reboot.c#L484 ,以及http://lxr.free-electrons.com/source/arch /x86/realmode/rm/reboot.S用于在回退到“真实”(16位分段)模式后实际执行跳转到FFFF:0000的代码。

代码试图跳转到x86 CPU在上电时开始执行的地址,即“上电复位向量”( 源 )。

这是一种依赖于系统(即:非便携式)重启机器的方法。 该程序运行的目标操作系统是什么? 是DOS(我假设)。 尝试在虚拟机中运行它并找出答案。

如果您希望这在其他平台上运行,您需要编写一些特定于平台的内容,如下所示:

 #ifdef __linux__ system("shutdown -P now"); #elif _WIN32 #if (WINVER == NTDDI_WIN7) // Windows 7 system("C:\\WINDOWS\\System32\\shutdown /s"); #endif #if ((WINVER <= NTDDI_WINXPSP3) && (WINVER >= NTDDI_WINXP)) // Windows XP system("C:\\WINDOWS\\System32\\shutdown -s"); #endif #else #error System not recognized #endif