Chinaunix首页 | 论坛 | 博客
  • 博客访问: 174888
  • 博文数量: 30
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 440
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-23 19:45
文章分类

全部博文(30)

文章存档

2016年(2)

2010年(3)

2009年(8)

2008年(17)

我的朋友

分类: LINUX

2009-05-21 10:46:55

一个程序经过编译连接后形成的地址空间是一个虚拟地址空间,而Linux在内存寻址时简化了分段机制,使得虚拟地址与线性地址是一致的,比如程序test_wait.c代码如下:

#include

#include                                                                                           

#include

 

int main(int argc, char **argv)

{

        int i;

        unsigned char *buff;

 

        buff = (char *)malloc(sizeof(char)*1024);

        printf("pid is :%d\n", getpid());

        for (i = 0; i < 60; i++) {

                sleep(60);

        }  

 

        return 0;

}

经过编译后形成的文件是test_wait,然后用命令objdump反汇编后如下(只取部分代码):

$ objdump -d test_wait

test_wait:     file format elf32-i386

 

Disassembly of section .init:

 

08048304 <_init>:

 8048304:   55                       push   %ebp

 8048305:   89 e5                    mov    %esp,%ebp

 8048307:   53                       push   %ebx

 8048308:   83 ec 04                 sub    $0x4,%esp

 804830b:   e8 00 00 00 00           call   8048310 <_init+0xc>

 8048310:   5b                       pop    %ebx

 8048311:   81 c3 e4 1c 00 00        add    $0x1ce4,%ebx

 8048317:   8b 93 fc ff ff ff        mov    -0x4(%ebx),%edx

 804831d:   85 d2                    test   %edx,%edx

 8048301:   e8 2e 00 00 00           call   8048334 <__gmon_start__@plt>

 8048306:   e8 15 01 00 00           call   8048420

可以看到,其中的地址就是虚拟地址,整个虚拟地址空间大小为3GB,再加上可以通过系统调用进入内核的1GB空间,于是每个进程可以拥有4GB的虚拟地址空间(也叫虚拟内存)。某个进程的虚拟地址空间可以通过/proc文件系统看到:

$ ./test_wait

pid is :9840

重新开一个终端:

cat /proc/9840/maps

08048000-08049000 r-xp 00000000 08:01 212891     /home/chen/mem/test_wait

08049000-0804a000 r--p 00000000 08:01 212891     /home/chen/mem/test_wait

0804a000-0804b000 rw-p 00001000 08:01 212891     /home/chen/mem/test_wait

096d5000-096f6000 rw-p 096d5000 00:00 0          [heap]

b7dee000-b7def000 rw-p b7dee000 00:00 0

b7def000-b7f47000 r-xp 00000000 08:01 409724     /lib/tls/i686/cmov/libc-2.8.90.so

b7f47000-b7f49000 r--p 00158000 08:01 409724     /lib/tls/i686/cmov/libc-2.8.90.so

b7f49000-b7f4a000 rw-p 0015a000 08:01 409724     /lib/tls/i686/cmov/libc-2.8.90.so

b7f4a000-b7f4d000 rw-p b7f4a000 00:00 0

b7f59000-b7f5c000 rw-p b7f59000 00:00 0

b7f5c000-b7f76000 r-xp 00000000 08:01 392460     /lib/ld-2.8.90.so

b7f76000-b7f77000 r-xp b7f76000 00:00 0          [vdso]

b7f77000-b7f78000 r--p 0001a000 08:01 392460     /lib/ld-2.8.90.so

b7f78000-b7f79000 rw-p 0001b000 08:01 392460     /lib/ld-2.8.90.so

bf964000-bf979000 rw-p bffeb000 00:00 0          [stack]

关于此文件的详细信息可以参看:

由上面的信息可以看到

08048000-08049000地址段的标志是r-xp(读,执行)是代码段,

08049000-0804a000的标志是rw-p(读写)是数据段

096d5000-096f6000是堆也叫空洞,只有当程序中调用malloc()申请空间时才有堆段。

bf964000-bf979000 是堆栈段

这样我们可以看到进程的用户空间的分配了。如下图:

 

 

可以看出代码段在最低地址依次往上是数据段,空洞、堆栈段在最高地址,栈指针向下移动。

进程的虚拟地址在保存在内核中的task_structPCB)结构中,定义如下:

struct task_struct { //进程结构体

//……

struct mm_struct *mm;//描述进程的整个用户空间

}

stuct mm_struct 结构中包含了虚拟空间的结构体字段mmap(struct vm_area_struct * mmap),所以可以通过模块编程来查看进程的虚拟地址空间。关于模块编程可以看这里:

,程序清单如下:

 #include                                                                                      

#include

#include

#include

 

static int pid;

 

module_param(pid,int,0644);

 

static int __init memtest_init(void)

{

        struct task_struct *p;

        struct vm_area_struct *temp;

 

        printk("My module worked!\n");

        p = find_task_by_vpid(pid);

        temp = p->mm->mmap;

 

        while(temp) {

                printk("start:%p\tend:%p\n", (unsigned long *)temp->vm_start,

(unsigned long *)temp->vm_end);

                temp = temp->vm_next;

        }  

 

        return 0;

}

static void __exit memtest_exit(void)

{

        printk("Unloading my module.\n");

        return;

}

module_init(memtest_init);

module_exit(memtest_exit);

MODULE_LICENSE("GPL");        

编译模块,运行刚才的程序test_wait,然后带参数插入模块,如下:

$ ./test_wait &

pid is :9413

$ sudo insmod mem.ko pid=9413

[ 2690.715913] My module worked!

[ 2690.715992] start:08048000    end:08049000

[ 2690.716005] start:08049000    end:0804a000

[ 2690.717029] start:0804a000    end:0804b000

[ 2690.717065] start:096d5000    end:096f6000

[ 2690.717096] start:b7dee000    end:b7def000

[ 2690.717126] start:b7def000     end:b7f47000

[ 2690.717157] start:b7f47000     end:b7f49000

[ 2690.717187] start:b7f49000     end:b7f4a000

[ 2690.717217] start:b7f4a000     end:b7f4d000

[ 2690.717248] start:b7f59000     end:b7f5c000

[ 2690.717304] start:b7f5c000     end:b7f76000

[ 2690.717334] start:b7f76000     end:b7f77000

[ 2690.717364] start:b7f77000     end:b7f78000

[ 2690.717395] start:b7f78000     end:b7f79000

[ 2690.717425] start:bf964000     end:bf979000

可以看出和刚才/proc文件系统中的地址是一样的。

在任意一个时刻,一个CPU只有一个进程在运行,所以虽然有时候很多进程的虚拟地址值有相同的,但是由于每次只有一个进程运行,在当某个进程运行时cpu就将其虚拟地址也切换进来,这样就保证了每个进程都拥有4GB的地址空间。

阅读(2356) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~