You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下共享对象(.so)代码段未在进程间共享的原因探究

为什么修改共享对象代码段不会影响其他进程实例?

核心原因:写时复制(Copy-On-Write,COW)机制

共享库的.text段确实会被多个进程只读共享物理内存页,但当你通过mprotect()修改页权限并写入数据时,操作系统会触发写时复制机制:

  • 当进程尝试写入原本只读的共享页时,内核会为该进程复制一份物理页的私有副本
  • 后续该进程的读写操作都针对这份私有副本,其他进程仍使用原始的共享物理页
  • 这就导致你的修改只对当前进程生效,完全不会影响其他进程

你的代码中的关键细节

  1. mprotect()的作用:你将页权限修改为PROT_READ | PROT_WRITE | PROT_EXEC,打破了原本的只读属性,为写时复制的触发创造了条件
  2. 写入操作触发COW:当执行*ip = (int)time(NULL);时,内核检测到对只读共享页的写入,立刻复制私有页,后续该进程的getval()读取的是自己私有页里的数值

额外补充

  • 共享库的.text段默认是只读的,设计目的就是让多个进程共享同一份物理内存以节省资源
  • 如果要实现进程间共享可修改的数据,应该使用共享内存段(如shmget/mmap带MAP_SHARED)或者其他进程间通信(IPC)机制

复现代码

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);
    }
}

int 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);
    }
}

run.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

内容的提问来源于stack exchange,提问作者zomega

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 07:15:18