4

好的,所以我知道我们所有的 C/C++ 程序员都曾遇到过我们不合时宜的克星,恶魔信号 SIGSEGV,分段错误。现在,我理解(强调过去时)这是某种形式的故障安全/检查系统,它位于由神奇的 GCC(或 g++)编译器或您拥有的机器代码的某些部分中。

但!今天,我在虚拟化 Arch Linux 系统上使用了一些带有良好旧 NASM 的 x86 汇编程序,令我惊讶和懊恼的是,我的编码工作再次被邪恶的 SegFault 挫败。

这是产生可怕信号的代码:

mov eax, 0x7
mov [0xB8000], eax

现在,我知道 Linux 内核将您组装的程序加载到一个 shell 中并从那里执行它,但我认为这个 MOV 指令与处理器进行了 1 对 1 的交互,内核到底如何检测到我正在尝试访问一个它不想让我留下一点记忆,然后停止指令?

我不假装理解当你的程序加载到 shell 时究竟发生了什么,你在 shell 中拥有什么权限,甚至不知道 shell 是什么或它是如何工作的,但我曾经确信 ASM 给了你完全控制处理器。这个神奇的内核如何干扰我对处理器的直接命令,为什么我在编写本质上是纯机器代码时仍然被迫通过这个操作系统命令链?:O

4

2 回答 2

5

Linux 执行您的程序在用户模式下运行x86上的ring 3)。此外,它使用基于页面的内存保护来限制您的程序可以访问的内存位置。特别是,您的程序尝试写入(VGA 帧缓冲区),它没有修改权限。处理器的MMU检测到这一点,并引发CPU 异常。Linux 内核处理此异常,并将其转换为段违规信号 0xB8000. 假设您没有为您的信号设置自定义处理程序,那么内核会终止您的进程。为了避免这种情况并获得对硬件的完全访问权限,您需要编写一个 Linux 设备驱动程序,该驱动程序将在具有完全权限的内核模式(x86 上的环 0)下运行,或者通过编写自己的操作系统完全绕过 Linux 。

于 2010-08-04T03:26:42.033 回答
4

MMU 已保护您尝试访问的内存,因此当您执行违反某些权限的指令时,会生成中断/处理器异常。该异常由内核处理并作为分段错误信号转发给您的应用程序。由于您的应用程序不处理 SIGSEGV,因此它被终止,并且控制权返回到您的 shell。

如果您想要“对处理器的完全控制”,您需要在较低级别编写代码(如果您想保持操作系统运行,则在内核中编写代码,或者如果您愿意,您需要编写自己的操作系统或执行程序自己处理所有事情)。

编写汇编程序与编写 C 程序没有什么不同,只是你可能会生成一些 C 编译器不会发出的奇怪指令。仅基于编写程序的语言,不会授予程序特殊的权限或能力。

于 2010-08-04T03:21:27.137 回答