1、先看看下面代码,代码中额外增加了获取进程代码段和数据段的。
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
int a = 0;
int main()
{
FILE *fp = NULL;
char *line = NULL;
char *result = NULL;
pid_t pid = 0;
int t_addr = 0;
size_t len = 0;
int fd = -1;
long long int tso_addr= 0;
char mapsfile[30] = {0x00};
pid = getpid();
sprintf(mapsfile, "/proc/%d/maps", pid);
printf("pid:%i maps: %s\n", pid, mapsfile);
fp = fopen(mapsfile, "r");
if (!fp) {
printf("open error.\n");
return -1;
}
/*r-xp对应着程序的代码段*/
while ((getline(&line, &len, fp)) != -1) {
if ((strstr(line, "r-xp")) && (strstr(line, "hello"))) {
result = strtok(line, "-");
t_addr = strtol(result, NULL, 16);
printf("text_addr: 0x%x\n", t_addr);
}
if ((strstr(line, "r-xp")) && (strstr(line, "libuClibc-1.0.31.so"))) {
result = strtok(line, "-");
tso_addr = strtoll(result, NULL, 16);
printf("res=%s, text_so_addr: 0x%x\n", result, tso_addr);
}
}
if (line)
free(line);
fclose(fp);
printf("data_addr: 0x%p\n", &a);
/*传入虚拟地址给内核,在内核驱动中获取物理地址*/
fd = open("/dev/text", O_RDWR);
param.addr = t_addr;
ioctl(fd, 1, ¶m);
param.addr = (int)&a;
ioctl(fd, 1, ¶m);
param.addr = tso_addr;
ioctl(fd, 1, ¶m);
close(fd);
while (1) {
sleep(2);
}
return 0;
}
假如上面的应用程序在同一时间同时运行两份,数据段是两份,那么代码段也是两份嘛?
2、验证
应用程序运行过程中,需要获取代码段的地址(代码段是一个虚拟地址),同时转换到物理地址,看看物理地址是不是同一个。(ARM 32环境为例)参考:虚拟地址如何访问到物理地址_sydyh43的博客-CSDN博客
2.1、在用户态获取到程序和动态库的代码段地址,和程序的数据段地址
2.2、将地址传入到内核态,在内核态完成地址的翻译,得到物理地址
3、结果
从输出的信息可以看出,程序和动态库的代码段物理地址相同,用的是同一份;数据段的物理地址不同。