共享对象(.so文件)的代码(也称为.Text部分)通常在进程之间共享.你可以读到here.

我写了一个小例子,事情似乎表现得不同.

In short:该程序证明对共享对象的代码段所做的更改不会影响该程序的其他实例.因此,共享对象的代码段不会在进程之间共享.

Long explanation:代码由一个程序(main.c)组成,该程序加载一个.so文件(mylib.c).

该库由一个返回整数的函数组成.该整数与机器指令一起存储在代码段中.如果您不相信整数存储在代码段中,您可以运行objdump -d libmy.so.

程序加载库,然后修改共享对象的代码段中的整数.在此之前,程序运行mprotect()以避免分段错误.该值正在更改为当前时间戳.

现在我运行程序两次,延迟2秒,因此每个实例都将自己的值写入.so代码部分.令人惊讶的是,第一个实例的值没有被第二个实例的值覆盖.

那件事怎么可能?

我只在x64上测试过这个程序.只需保存文件并运行bash脚本即可.

Libmy.c:

int getval()
{
    return 123;
}

Main.c:

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/mman.h>

int getval();

void unprotect(uint64_t addr)
{
    uint64_t pagesize = sysconf(_SC_PAGE_SIZE);
    addr -= addr % pagesize;
    if (mprotect((void*)addr, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
    {
        printf("mprotect failed\n");
        exit(1);
    }
}

void main()
{
    for (int i = 0; i < 30; i++)
    {
        int* ip = (int*)((char*)&getval + i);
        if (*ip == 123)
        {
            printf("found value at offset %i\n", i);
            unprotect((uint64_t)ip);
            unprotect((uint64_t)ip + 3);
            *ip = (int)time(NULL);
            printf("value changed successfully\n");
            break;
        }
    }

    while (1)
    {
        printf("getval() returns %i\n", getval());
        sleep(1);
    }
}

运行.bash:

#!/bin/bash
set -e
gcc -shared -fPIC -o libmy.so libmy.c
gcc main.c -L. -lmy -Wl,-rpath . -o bin
./bin &
sleep 2
./bin

推荐答案

共享对象使用MAP_PRIVATE标志进行映射.这意味着内存最初在所有用户之间共享,但为每页设置了"写入时复制"标志.因此,如果一个进程修改了内存,它们会得到自己的副本,这不会影响链接到同一目标文件的其他进程.

显然,这对于数据部分是必要的,因 for each 进程都希望对此进行本地更改.但对于文本部分也是这样做的,尽管它默认是只读的.正如您所发现的,您可以覆盖只读标志,但因为它仍然是COW,所以当您写入它时,您会得到一个私有副本.

C++相关问答推荐

为什么在传输 Big Data 时共享内存段的运行时间比管道更长?

strftime函数中%s的历史意义是什么?为什么没有记录?

intellisense不工作,甚至已经下载了c/c++扩展

当main函数调用被重构时,C函数给出错误的结果

数据包未从DPDK端口传输到内核端口

无效指针值在函数调用之间莫名其妙地改变

在c++中使用堆栈的有效括号

ATmega328P EEPROM未写入

C++中矢量类型定义和数据保护的高效解决方案

双指针指向常量双指针的指针类型赋值不兼容

为什么数组的最后一个元素丢失了?

';\n&39;和';\r&39;中的';\n&39;之间有什么关系?

C语言中浮点数的取整方式浮点数尾数超过23位时如何取整剩余部分

我可以创建适用于不同endian的 colored颜色 struct 吗?

共享目标代码似乎不能在Linux上的进程之间共享

Malloc和对齐

const struct 成员的 typedef 中的灵活数组大小

使用 GCC 将一个函数中初始化的 struct 体实例通过指针传递到 C 中的另一个函数会产生不同的结果

如何使用 raylib 显示数组中的图像

我怎样才能用c语言正常运行这两个进程?