軟件是對質量的不懈追求

          進程的地址空間

          一個程序經過編譯連接后形成的地址空間是一個虛擬地址空間,而Linux在內存尋址時簡化了分段
          機制,使得虛擬地址與線性地址是一致的,比如程序test_wait.c代碼如下:
              #include <stdio.h>
              #include 
          <stdlib.h>                                                                                          
              #include 
          <unistd.h>
              
          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]

          關于此文件的詳細信息可以參看:
          http://www.kerneltravel.net/?p=287
          由上面的信息可以看到
          08048000-08049000地址段的標志是r-xp(讀,執行)是代碼段,
          08049000-0804a000的標志是rw-p(讀寫)是數據段
          096d5000-096f6000是堆也叫空洞,只有當程序中調用malloc()申請空間時才有堆段。
          bf964000-bf979000 是堆棧段
          這樣我們可以看到進程的用戶空間的分配了。如下圖:
           
           

          可以看出代碼段在最低地址依次往上是數據段,空洞、堆棧段在最高地址,棧指針向下移動。
          進程的虛擬地址在保存在內核中的task_struct(PCB)結構中,定義如下:
          struct task_struct { //進程結構體
          //……
          struct mm_struct *mm;//描述進程的整個用戶空間
          }
          而stuct mm_struct 結構中包含了虛擬空間的結構體字段
          mmap(struct vm_area_struct * mmap),所以可以通過模塊編程來查看進程的虛擬地址空間。
          關于模塊編程可以看這里:
          http://www.kerneltravel.net/?p=80,程序清單如下:


           #include <linux/module.h>                                                                                     
           #include 
          <linux/init.h>
           #include 
          <linux/interrupt.h>
           #include 
          <linux/sched.h>
           
          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的地址空間。

          posted on 2009-11-16 13:15 BlakeSu 閱讀(437) 評論(2)  編輯  收藏

          評論

          # re: 進程的地址空間[未登錄] 2009-11-17 09:07 Frank

          牛,內核呀!發了幾次都不成功,郁悶!  回復  更多評論   

          # re: 進程的地址空間 2009-11-17 10:54

          很核心啊,好好學習,天天向上  回復  更多評論   


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 宜城市| 环江| 彭山县| 大邑县| 荔浦县| 旌德县| 公主岭市| 曲麻莱县| 资阳市| 双城市| 阿城市| 江口县| 遵化市| 武穴市| 武威市| 且末县| 临猗县| 东海县| 太和县| 沂南县| 上犹县| 阿拉善右旗| 娱乐| 张家川| 邯郸县| 仁布县| 宝鸡市| 石门县| 铁岭市| 大兴区| 临高县| 长兴县| 东丽区| 高青县| 财经| 梨树县| 那坡县| 东乡族自治县| 稻城县| 玛沁县| 专栏|