共享对象(.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++相关问答推荐

为什么下面的C代码会进入无限循环?

ATmega328P USART发送字符重复打印

是否定义了数组指针类型转换为指针类型?""""

C指针算法在函数参数中的应用

LibpCap禁用监视器模式(C、MacOS)

C语言编译阶段与翻译阶段的关系

使用双指针动态分配和初始化2D数组

具有交换链获取和命令缓冲区提交的同步-危险-读后写错误

在CLANG中调试预处理器宏

Square不与Raylib一起移动

在另一个函数中使用realloc和指针指向指针

For循环中的变量行为不符合预期.[C17]

C++中PUTS函数的返回值

带有数组指针的 struct 在print_stack()函数中打印随机数

将不同类型的指针传递给函数(C)

中位数和众数不正确

nullptr_t 是否会 destruct 类型双关或指针转换?

inline 关键字导致 Clion 中的链接器错误

React Native Android C++ TurboModules 静态 C 库链接问题

在 C 语言中,为什么 10/3 应该给出 3.333 却给出 3.000? (保存 10 和 3 的变量被声明为double)