Operating system 覆盖内存映射的可执行文件时会发生什么情况?

Operating system 覆盖内存映射的可执行文件时会发生什么情况?,operating-system,execution,Operating System,Execution,在我对一个问题的评论之后,我很想知道当一个人重写一个可执行文件时会发生什么。我需要核实我对这件事的理解 假设我有/usr/bin/myprog。我运行它,所以操作系统加载/usr/bin/myprog,可能是通过 无论出于何种原因,该进程仍保留在内存中,我决定实际上我已经修复了一个bug,并覆盖了/usr/bin/myprog 因此,据我所知: 如果已加载myprog的实例,并且我替换了已加载myprog的文件,则myprog的实例不会被修改 如果我运行myprog的新实例,它将使用新代码

在我对一个问题的评论之后,我很想知道当一个人重写一个可执行文件时会发生什么。我需要核实我对这件事的理解

假设我有
/usr/bin/myprog
。我运行它,所以操作系统加载
/usr/bin/myprog
,可能是通过

无论出于何种原因,该进程仍保留在内存中,我决定实际上我已经修复了一个bug,并覆盖了
/usr/bin/myprog

因此,据我所知:

  • 如果已加载
    myprog
    的实例,并且我替换了已加载
    myprog
    的文件,则
    myprog
    的实例不会被修改
  • 如果我运行
    myprog
    的新实例,它将使用新代码
我说得对吗

然而,根据关于内存映射文件的文章,这种技术允许开发人员将文件的某些部分视为物理内存

所以我发现我对事物的理解存在矛盾。如果页面确实只是按需加载,那么假设
myprog
不是100%分页的,这篇维基百科文章暗示将从磁盘上的文件加载新页面,自从加载原始图像以来,该文件发生了变化

但是,我非常确定我的两个编译图像将不相同,并且每个文件的相关地址偏移量也不相同。因此,假设发生这种情况,指令指针将丢失。。。我非常确定操作系统不会将两个不同映像的部分作为同一进程的一部分加载到内存中

那么,对于程序的执行,内存映射/请求分页的组合是如何工作的呢?覆盖该文件是否会在每个可执行文件的页面上触发页面错误,以确保为当前运行的进程加载该文件

我用这个做了一个快速的实验:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char** argv)
{
    printf("Program resident...");
    while(1)
    {
        printf("??? Just notifying you I'm still here...\n");
        usleep(1000000);
    }

    return 0;
}
#包括
#包括
int main(int argc,字符**argv)
{
printf(“程序常驻…”);
而(1)
{
printf(“???只是通知您我还在这里…\n”);
美国LEEP(1000000);
}
返回0;
}
果然,我可以a)在这个可执行文件运行时替换它,b)它的输出没有改变

那么到底发生了什么?我特别感谢大家对我能做的事情的建议,看看会发生什么(Linux或Windows)

谢谢大家

编辑:我提到的引发这个问题的问题:

另外,我知道这与编程无关,而是更新可执行文件的结果。然而,我仍然很感兴趣,我想不出比这更好的地方了

  • 发生什么首先取决于您是否
    rm/usr/bin/myprog
    ,然后创建一个新的,或者您是否
    open()
    write()
    到现有的
    /usr/bin/myprog

  • 如果您
    rm
    旧的
    /usr/bin/myprog
    文件,然后创建一个同名的新文件,那么内核/文件系统驱动程序将为新版本提供一个新的inode,并且旧的inode将保留在
    /proc
    文件系统中,直到打开它的进程将其关闭。您现有的进程
    /usr/bin/myprog
    有自己的私有版本的文件,未经修改,直到它
    close()
    s文件描述符

  • 所有操作系统(Windows、Linux,可能是OS X)都使用按需分页内存映射(
    mmap()
    对于posix,我记不起Windows的等价物-
    VirtualAlloc()
    ?)来进行进程加载。这样,可执行文件中任何未被触及的部分都不会加载到内存中

  • 如果这是一个传统的
    mmap()
    'd文件,并且两个进程都打开/映射了它,并且在调用
    mmap()
    时都没有指定
    MAP\u PRIVATE
    (即写时复制),那么这两个进程基本上将查看相同的物理内存页,并且如果它们都被称为
    mmap()
    通过
    PROT_READ
    PROT_WRITE
    ,他们将看到彼此的修改

  • 如果这是一个传统的
    mmap()
    'd文件,而进程1已经打开/映射了它,然后进程2开始通过
    write()
    调用(而不是我的
    mmap
    调用)在硬盘上摆弄文件本身,那么进程1确实看到了这些更改。我猜内核会注意到文件正在被修改,并重新加载受影响的页面

  • 我不知道可执行图像是否有任何特殊的
    mmap()
    行为?如果我入侵了一个指向某个函数的指针并修改了代码,它会将页面标记为脏页面吗?脏页是否会被写回
    /usr/bin/myprog
    ?当我尝试此操作时,它会出现故障,因此我猜,虽然文本页面使用
    MAP\u SHARED
    进行映射,但它们也可能不会得到
    PROT\u WRITE
    ,因此在写入时会出现故障_当然,数据段也会被加载到内存中,这些数据段需要修改,但这些数据段可以标记为
    MAP\u PRIVATE
    (写时复制)-因此它们可能不会保持与
    /usr/bin/myprog
    文件的连接

  • 第6点涉及直接修改自身的可执行文件。第5点涉及在
    write()
    级别修改任意
    mmap()
    d文件。当我试图用
    write()
    在另一个进程中修改可执行文件(即
    mmap()
    'd)时,我不会得到与第5点相同的结果。我可以通过裸
    write()
    调用对可执行文件进行各种可怕的更改,但什么也没有发生。然后,当我退出进程并尝试再次运行它时,它崩溃了(当然,在我对可执行文件做了所有操作之后)。这使我困惑。我无法将参数排列到
    mmap()
    以使其