共享对象(.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