Linux下對物理地址的訪問

來源:互聯網
上載者:User
 Linux核心裡提供的/dev/mem驅動,為我們讀寫記憶體物理地址,提供了一個渠道。下面講述2種利用mem裝置檔案進行物理地址讀寫的方法,一種是裝置驅動的方法,另一種是系統調用的方法。
首先我們看下mem這個裝置檔案,/dev/mem是linux下的一個字元裝置,源檔案是~/drivers/char/mem.c,這個裝置檔案是專門用來讀寫物理地址用的。裡面的內容是所有實體記憶體的地址以及內容資訊。通常只有root使用者對其有讀寫權限。
 
    1.裝置驅動的方法

    下面是mem.c檔案裡定義的file_operations結構,提供了llseek,read,write,mmap以及open等方法。
    static struct file_operations mem_fops =
    {
        .llseek  = memory_lseek,
        .read  = read_mem,
        .write  = write_mem,
        .mmap  = mmap_mem,
        .open  = open_mem,
    };
    因此我們可以通過一般驅動的使用方法,將記憶體完全當作一個裝置來對對待。應用程式如下:
    #include <stdio.h>
    #include <fcntl.h>
    int main(void)
    {
        int fd;
        char *rdbuf;
        char *wrbuf = "butterfly";
        int i;
        fd = open("/dev/mem",O_RDWR);
        if(fd < 0)
        {
            printf("open /dev/mem failed.");
        }
        read(fd,rdbuf,10);
 
        for(i = 0;i < 10;i++)
        {
            printf("old mem[%d]:%c/n",i,*(rdbuf + i));
        }
        lseek(fd,5,0);
        write(fd,wrbuf,10);
        lseek(fd,0,0);//move f_ops to the front
        read(fd,rdbuf,10);
        for(i = 0;i < 10;i++)
        {
            printf("new mem[%d]:%c/n",i,*(rdbuf + i));
        }
 
        return 0;
    }

    執行結果如下:將記憶體最開始10個位元組的內容進行替換。
    [root@VOIP-IPCAM app]# ./memtest
    old mem[0]:b
    old mem[1]:u
    old mem[2]:t
    old mem[3]:t
    old mem[4]:e
    old mem[5]:r
    old mem[6]:f
    old mem[7]:l
    old mem[8]:y
    old mem[9]:!
    new mem[0]:b
    new mem[1]:u
    new mem[2]:t
    new mem[3]:t
    new mem[4]:e
    new mem[5]:b
    new mem[6]:u
    new mem[7]:t
    new mem[8]:t
    new mem[9]:e

    2.系統調用的方法

    細心的你可能會發現,既然你前面說了這個檔案裡存放的就是記憶體的地址及內容資訊,那我可不可以直接查看到呢,答案是:可以的。linux核心的開發人員為我們提供了一個命令hexedit,通過它就可以將/dev/mem的內容顯示出來(如果你使用cat /dev/mem將會看到亂碼),執行hexedit /dev/mem的結果如下:
    00000000   62 75 74 74  65 62 75 74  74 65 72 66  6C 79 21 20  butterfly!
    00000010   20 20 20 20  20 20 20 20  20 20 20 20  20 20 20 20
    00000020   20 20 20 20  20 20 20 20  20 20 20 20  20 20 20 20
    00000030   6F EF 00 F0  6F EF 00 F0  57 EF 00 F0  6F EF 00 F0  o...o...W...o...
    00000040   02 11 00 C0  4D F8 00 F0  41 F8 00 F0  34 85 00 F0  ....M...A...4...
    00000050   39 E7 00 F0  59 F8 00 F0  2E E8 00 F0  D2 EF 00 F0  9...Y...........
    00000060   A4 E7 00 F0  F2 E6 00 F0  6E FE 00 F0  53 FF 00 F0  ........n...S...
    00000070   53 FF 00 F0  A4 F0 00 F0  C7 EF 00 F0  1C 42 00 C0  S............B..
    從可見,最左邊顯示的是地址,接下來24列顯示的是各記憶體位元組單元內容的ASCII碼資訊,最右邊顯示的是對應的字元資訊。讓人欣慰的是,這個檔案可以直接修改,按下tab鍵進入修改模式,修改過程中修改內容會以粗體顯示,按下F2儲存後粗體消失。上面的butterfly就是通過這種方式修改的。
    既然記憶體的地址以及內容資訊全部被儲存在mem這個裝置檔案裡,那麼我們可以想到通過另外一種方式來實現對物理地址的讀寫了。那就是將mem裝置檔案和mmap系統調用結合起來使用,將檔案裡的實體記憶體地址映射到進程的地址空間,從而實現對記憶體物理地址的讀寫。下面談一下mmap系統調用。
    mmap的函數原型為:void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset),該函數定義在/usr/include/sys/mman.h中,使用時要包含:#include<sys/mman.h>,mmap()用來將某個檔案中的內容映射到進程的地址空間,對該空間的存取即是對該檔案內容的讀寫。參數說明如下:
    start:指向欲映射到的地址空間的起始地址,通常設為null或者0.表示讓系統融自動選定地址,映射成功後該地址會返回。
    length:表示映射的檔案內容的大小,以位元組為單位。
    prot:表示映射地區的保護方式,有如下四種組合:
      --PROT_EXEC 映射地區可執行 ,
      --PROT_READ 映射地區可讀 ,
      --PROT_WRITE 映射地區可寫,
      --PROT_NONE 映射地區不能被訪問
    flags:映射地區的一些特性,主要有:
      --MAP_FIXED 如果映射不成功則出錯返回,
      --MAP_SHARED 對映射地區的寫入資料會寫回到原來的檔案
      --MAP_PRIVATE 對映射地區的寫入資料不會寫回原來的檔案
      --MAP_ANONYMOUS
      --MAP_DENYWRITE 只允許對映射地區的寫入操作,其他對檔案直接寫入的操作將被拒絕
      --MAP_LOCKED 鎖定映射地區
    在調用mmap()時,必須要指定MAP_SHARED或MAP_PRIVATE。
    fd:open()返回的檔案描述符。
    offset:為被對應檔的位移量,表示從檔案的哪個地方開始映射,一般設定為0,表示從檔案的最開始位置開始映射。offset必須是分頁大小(4096位元組)的整數倍。
    應用程式如下:
    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/mman.h>//mmap head file
    int main (void)
    {
       int i;
       int fd;
       char *start;
       char *buf = "butterfly!";
 
       //open /dev/mem with read and write mode
       fd = open ("/dev/mem", O_RDWR);
       if (fd < 0)
       {
           printf("cannot open /dev/mem.");
           return -1;
       }
 
       //map physical memory 0-10 bytes
       start = (char *)mmap(0, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
       if(start < 0)
       {
          printf("mmap failed.");
          return -1;
       }
       //Read old value
       for (i = 0; i < 10; i++)
       {
           printf("old mem[%d]:%c/n", i, *(start + i));
       }
       //write memory
       memcpy(start, buf, 10);
       //Read new value
       for (i = 0;i < 10;i++)
       {
          printf("new mem[%d]:%c/n", i,*(start + i));
       }
       munmap(start, 10); //destroy map memory
       close(fd);  //close file
       return 0;
    }
    程式執行結果如下:
    [root@VOIP-IPCAM app]# ./rwphy
    old mem[0]:b
    old mem[1]:u
    old mem[2]:t
    old mem[3]:t
    old mem[4]:e
    old mem[5]:b
    old mem[6]:u
    old mem[7]:t
    old mem[8]:t
    old mem[9]:e
    new mem[0]:b
    new mem[1]:u
    new mem[2]:t
    new mem[3]:t
    new mem[4]:e
    new mem[5]:r
    new mem[6]:f
    new mem[7]:l
    new mem[8]:y
    new mem[9]:!
    借用別人的一句話作為結束語:
    “/dev/mem是個很好玩的東西,你竟然可以直接存取實體記憶體。這在LINUX下簡直是太神奇了,這種感覺象一個小偷打算偷一個銀行,可是這個銀行戒備森嚴,正當這個小偷苦無對策時,突然發現在一個不起眼的地方有個後門,這個後門可以直接到銀行的金庫.”

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.