Restart a computer using function pointers in C

后端 未结 3 893
一整个雨季
一整个雨季 2021-01-28 00:37

I was learning about function pointers in C when I came across a program that restarts the computer upon execution.

void (*f) (void);
f=(void (*)(void) MK_FP(0xF         


        
相关标签:
3条回答
  • 2021-01-28 00:45

    The code is attempting to jump to the address where x86 CPUs start executing at power-on, aka the "Power On Reset Vector" (source).

    0 讨论(0)
  • 2021-01-28 01:06

    About programs that manually construct function pointers from numeric literals and call them, the C standard says only that the behavior is undefined. That means you can't expect the program to behave the same way from computer to computer, or even from run to run on the same computer.

    About this particular program, we can make an educated guess about what it was meant to do and under what circumstances it will actually do that:

    The original operating system for the original IBM PC, commonly known as MS-DOS, started executing code at the segmented address FFFF:0000 upon power-on. (Some sources say F000:FFF0 instead -- for reasons too tedious to get into here, that is the same physical address, but expressed a different way and possibly behaving differently depending on what code is at that location.) Because this OS was so bare-bones, jumping to that location after the machine was up and running would perform an approximation to a warm reboot.

    On the assumption that your MK_FP macro constructs a segmented function pointer from segment and offset values, then, when your program is executed on an IBM PC running MS-DOS, it jumps to FFFF:0000 and performs an approximation to a warm reboot.

    On a more modern operating system (including all current OSes for the descendants of the IBM PC) this program is guaranteed not to reboot the computer, because unprivileged user-mode programs are not allowed to reboot the computer. Moreover, the MK_FP() operation itself doesn't make sense in a modern 32- or 64-bit user mode program, because they run in flat address spaces. The code may compile, but it almost certainly winds up calling an address that has no memory mapped to it, so I would expect the program to crash. But the rest of the OS will just keep on going like nothing happened. If you ran the program inside a DOS emulator, it might reboot the emulator, but again, the rest of the OS will just keep on going.

    It is possible to write a program that reboots a modern OS -- indeed, you already have at least one such program on your computer, or you'd have no way of rebooting it short of the physical power switch! -- but it has to ask the kernel nicely, using a special system call (Unix-family: reboot(2); Windows: ExitWindowsEx) and it has to be running with special privileges or the call will fail.

    That said, a jump to FFFF:0000 plus a bunch of ancillary chicken-waving is one of the low-level operations that current versions of Linux may use to trigger a reboot on x86-based machines. It's only tried if several other things fail, but it's in there. See http://lxr.free-electrons.com/source/arch/x86/kernel/reboot.c#L484 for an outline of the overall procedure, and http://lxr.free-electrons.com/source/arch/x86/realmode/rm/reboot.S for the code that actually executes the jump to FFFF:0000 after dropping back to "real" (16-bit segmented) mode.

    0 讨论(0)
  • 2021-01-28 01:10

    This is a system dependent (ie: non-portable) approach to restarting the machine. What is the intended OS for this program to run on? Is it DOS (I'm assuming). Try running it inside a virtual machine and find out.

    If you want this to work on other platforms, you'll need to write some platform specific stuff, like so:

    #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
    
    0 讨论(0)
提交回复
热议问题