【问题标题】:Restart a computer using function pointers in C使用 C 中的函数指针重新启动计算机
【发布时间】:2014-12-16 05:43:02
【问题描述】:

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

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

(void (*)(void)) 部分不在提供的原始文本中,我必须添加此部分才能编译代码。这是如何工作的?

非常感谢。

【问题讨论】:

  • 这可能适用于运行 DOS 的机器;它可能无法在运行 Windows 的机器上运行,并且绝对不会在运行 Unix 的机器上运行。你在运行DOS吗?而且 Turbo C++ 3.0 与其说是“老派”,不如说是太老了,不能还在学校(它于 1991 年发布!)。
  • MK_FP 在哪里定义?
  • Joel Cornett,它在 中定义,但这不是这里的问题。
  • Jonathan Leffler: 实际上我是在 window 上运行的 :( 我所有擅长编码的朋友都转向了 Codeblock 等等,当我使用诸如近指针和远指针之类的东西时,他们只是不不知道我在写什么。所以我很确定这是老派
  • 你为什么要在 2014 年编写 MS-DOS 程序?你的朋友不知道你在说什么,因为你说的是​​过时的技术。

标签: c function-pointers


【解决方案1】:

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

关于这个特定的程序,我们可以有根据地猜测它的目的是什么,以及在什么情况下它实际上会这样做:

最初的 IBM PC 的原始操作系统,通常称为 MS-DOS,在开机时开始在分段地址 FFFF:0000 处执行代码。 (一些消息来源说 F000:FFF0 代替 - 因为太乏味而无法进入这里,这是 相同的物理地址,但表达方式不同,并且可能表现不同,具体取决于该位置的代码.) 因为这个操作系统非常简单,所以在机器启动并运行后跳转到该位置将执行近似于热重启。

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

在更现代的操作系统(包括 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 的代码。

【讨论】:

  • 整洁的发现。我也希望 linux 有一种更“复杂”的方法来触发热启动。
  • @Dogbert 我又看了一遍,我错了——首先尝试了 ACPI、EFI 和基于键盘控制器的传统技术。 (天哪,IBM 在键盘控制器上堆放了许多杂项功能,不是吗?)(另外,自从我上次详细查看 Linux 的内脏以来,我对 Linux 变成意大利面条的程度非常不满意。那是...... 1998 年。我老了。)
  • @DangManhTruong 我不知道你为什么会想要编写 16 位实模式 DOS 程序?但无论如何,我希望我对你有所帮助。
【解决方案2】:

代码试图跳转到 x86 CPU 在开机时开始执行的地址,也就是“开机复位向量”(source)。

【讨论】:

    【解决方案3】:

    这是一种依赖于系统的(即:非便携式)重启机器的方法。该程序运行的预期操作系统是什么?是 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
    

    【讨论】:

    • 或者您可以致电rebootExitWindowsEx
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 2014-12-24
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多