【问题标题】:Can PC register point to a memory zone different from text segment?PC寄存器可以指向与文本段不同的内存区域吗?
【发布时间】:2020-09-02 07:04:20
【问题描述】:

我有两个关于PC注册的问题:

  1. 如果 CPU 的 PC 寄存器指向不在进程文本段中的内存单元,CPU 会崩溃吗?如果是这样,是进程刚刚终止还是机器死了?

  2. 当 cpu 执行一个进程时,它会通过递增 PC 来不断迭代指令。假设 PC 指向最后一条指令。 CPU 是如何知道进程已经完成而不增加 PC 的?

对于第二个问题,我认为可以通过查看堆栈中的帧数来完成。如果我们在最后一帧调用 return,则该过程通常已完成。但这就是实际所做的吗?

【问题讨论】:

    标签: process operating-system cpu-registers


    【解决方案1】:

    在情况 1 中,当程序计数器指向无效地址时,处理器会引发异常,因为 MMU 将指示故障。然后操作系统通常会终止该进程,例如与 SIGSEGV。您可以在 C 中通过执行 ((void (*) (void)) (0xDEADBEEF)) ();(替换为任何无效地址)轻松地尝试此操作。如果这么简单的内存故障导致机器崩溃,那将是一个巨大的安全问题!

    如果这样的无效访问发生在内核空间内,则取决于内核是否将该位置配置为在 MMU 中不可访问。如果是,CPU 将再次引发异常,作为响应,内核可以例如打印错误信息。如果不是,则行为很大程度上取决于所涉及的 CPU 和地址;可能有一些硬故障异常导致系统崩溃或根本没有任何反应。

    情况 2 永远不应该发生。当 C 中的 main() 函数返回时,C 运行时库执行 exit 系统调用,之后操作系统将终止该进程。如果您使用汇编语言编写代码,则必须在程序退出时手动调用该系统调用。注意main()函数之后,内存中可能还有其他函数,当然应该main()返回之后执行。程序文本段中的最后一条指令需要是对某些有效指令的某种跳转/返回/调用;如果它是像add 这样的“普通”指令,CPU 将在此之后尝试执行无效的内存位置,在这种情况下适用 1(程序终止/崩溃)。当然在C程序中,所有的代码都是按函数组织的,每个函数都以返回/跳转指令结束,所以C程序文本段中的最后一条指令确实是返回/跳转。 p>

    【讨论】:

    • 感谢您的回答!对于案例2的答案,如果汇编程序没有调用exit怎么办?
    • 那么程序会做一些未定义的事情;当 CPU 尝试执行文本段之外的内存位置时,可能会崩溃,该内存位置尚未被操作系统配置为现有和可执行,这会导致异常。
    • 对于案例1,是否与分段有关,并且每个分段都有其访问权限?如果是这样,我想 cpu 将它的每个寄存器映射到它们可以指向的段(PC 到文本,SP 到堆栈,......)但我不确定这个映射存储在哪里?
    • 它与 MMU 页面有关。操作系统为在可执行文件中找到的程序段分配MMU页面,并根据需要将MMU页面配置为可读/可执行/可写。要启动程序,操作系统会将 PC 设置为程序入口点(通常称为_start,在文件头中定义)。然后程序有责任不将其设置为无效值(即跳转到无效地址)。
    • 不检查 PC、SP、... 寄存器的内容。仅检查内存访问。由于每条指令都会自动访问 PC,因此将 PC 指向无效地址将导致立即崩溃。让 SP 指向无效地址只会在您访问包含的地址时崩溃。内存单元不能包含无效内容,但 OS+MMU 可以禁止访问某些位置,因此如果您尝试访问它们,程序将终止;实际访问永远不会发生,因为之前发生过异常。
    猜你喜欢
    • 1970-01-01
    • 2016-08-26
    • 1970-01-01
    • 2014-07-29
    • 2012-06-08
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 2022-06-22
    相关资源
    最近更新 更多