• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-80  評論-24  文章-0  trackbacks-0
                  開發WinixJ的第一步工作我打算模仿Linux。
                  Linux是先將bootsect、setup、head、system等文件壓縮成一個IMAGE文件,然后再dd進軟盤,之后bootsect開始加載過程。我打算采用這種方法,因為這種方法可以省去將軟盤做成某種格式然后用晦澀的匯編在boot中尋找loader、kernel加載。不過不同的地方也很明顯:Linux0.11處理的system文件是a.out格式的二進制文件,這種文件格式非常簡單,因此相對容易加載進內存;但是WinixJ在Linux3.0.0.12下開發,此時的GCC已經不支持a.out格式的輸出,因此我只能將WinixJ內核編譯為ELF格式的二進制文件,而ELF格式的文件相對a.out要復雜的多,因此我們開發了proc_kernel.c文件專門處理ELF格式文件,該程序產生kernel.map輸出文件。
            先把代碼貼出:

              1 #include <stdio.h>
              2 #include <stdlib.h>
              3 #include <string.h>
              4 #include <unistd.h>
              5 #include <sys/stat.h>
              6 
              7 typedef    unsigned int    Elf32_Addr;
              8 typedef    unsigned short    Elf32_Half;
              9 typedef unsigned int    Elf32_Off;
             10 typedef unsigned int    Elf32_Sword;
             11 typedef unsigned int    Elf32_Word;
             12 
             13 #define EI_NIDENT    16
             14 #define MAX_BUF_LEN    1024
             15 
             16 //ELF文件的ELF header結構
             17 typedef struct
             18 {
             19     unsigned char    e_ident[EI_NIDENT]; //ELF魔數
             20     Elf32_Half        e_type; //文件類型
             21     Elf32_Half        e_machine; //支持的機器架構
             22     Elf32_Word        e_version; //版本號
             23     Elf32_Addr        e_entry; //程序的入口地址,在編譯內核的時候可由ld程序手工指定
             24     Elf32_Off        e_phoff; //program header在文件中的偏移量
             25     Elf32_Off        e_shoff; //section header在文件中的偏移量
             26     Elf32_Word        e_flags; //標志
             27     Elf32_Half        e_ehsize; //ELF頭的大小
             28     Elf32_Half        e_phentsize; //每個program header entry的大小
             29     Elf32_Half        e_phnum; //program header entry的數量
             30     Elf32_Half        e_shentsize; //每個section header entry的大小
             31     Elf32_Half        e_shnum; //section header entry的數量
             32     Elf32_Half        e_shstrndx;
             33 } Elf32_Ehdr;
             34 #define ELFHDR_LEN sizeof(Elf32_Ehdr)
             35 
             36 //ELF文件的program header結構
             37 typedef struct
             38 {
             39     Elf32_Word        p_type; //該頭所指向的program segment的類型
             40     Elf32_Off        p_offset; //該頭所指向的program segment在文件中的偏移
             41     Elf32_Addr        p_vaddr; //該頭所指向的program segment加載進內存后的虛擬地址
             42     Elf32_Addr        p_paddr; //該頭所指向的program segment加載進內存后的物理地址
             43     Elf32_Word        p_filesz; //該頭所指向的program segment在文件中的大小
             44     Elf32_Word        p_memsz; //該頭所指向的program segment在內存中的大小
             45     Elf32_Word        p_flags;
             46     Elf32_Word        p_align;
             47 }Elf32_Phdr;
             48 #define PHDR_LEN sizeof(Elf32_Phdr)
             49 
             50 //輸出到kernel.map文件中的時候,對每一個program segment,
             51 //都有一個Seghdr開頭,表征該段的信息,包括段的大小,以及段
             52 //的起始虛擬地址
             53 typedef struct
             54 {
             55     int memsz;
             56     int vaddr;
             57 }Seghdr;
             58 #define SEGHDR_LEN sizeof(Seghdr)
             59 
             60 #define FILE_NAME_LEN 50
             61 //緩沖區
             62 unsigned char buffer[MAX_BUF_LEN];
             63 char infilename[FILE_NAME_LEN];
             64 char outfilename[FILE_NAME_LEN];
             65 FILE *ifp, *ofp;
             66 
             67 static void usage()
             68 {
             69     fprintf(stderr, "Usage: proc_kernel [-r ../boot/boot] [-w ../Image]\n");
             70 }
             71 
             72 void die()
             73 {
             74     fclose(ifp);
             75     fclose(ofp);
             76     exit(1);
             77 }
             78 
             79 static void init()
             80 {
             81     strcpy(infilename, "../kernel/kernel"); //默認輸入文件為在頂層目錄的kernel子目錄中的內核文件
             82     strcpy(outfilename, "../kernel/kernel.map"); //默認輸出到頂層目錄的kernel子目錄中,文件名為kernel.map
             83 }
             84 
             85 static void proc_opt(int argc, char * const *argv)
             86 {
             87     int ch;
             88     opterr = 0//不顯示錯誤信息
             89 
             90     while ((ch = getopt(argc, argv, "r:w:h")) != -1)
             91     {
             92         switch (ch)
             93         {
             94             case 'r'//指定kernel文件名
             95                 strcpy(infilename, optarg);
             96                 break;
             97             case 'w'//指定輸出的系統映像文件名
             98                 strcpy(outfilename, optarg);
             99                 break;
            100             case 'h':
            101                 usage();
            102                 exit(1);
            103         }
            104     }
            105 }
            106 
            107 static void open_file()
            108 {
            109     //如果輸入的內核文件不存在
            110     if (0 != access(infilename, F_OK))
            111     {
            112         fprintf(stderr, "\"%s\": No such file.\n", infilename);
            113         exit(1);
            114     }
            115 
            116     //如果輸出的內核映像文件已經存在,報warning
            117     if (0 == access(outfilename, F_OK))
            118     {
            119         fprintf(stderr, "Warning: The file \"%s\" exists.\n", outfilename);
            120         fprintf(stderr, "But we will go on \n");
            121     }
            122 
            123     ifp = fopen(infilename, "r+");
            124     //如果不能打開輸入文件
            125     if (NULL == infilename)
            126     {
            127         fprintf(stderr, "cannot open the file \"%s\".\n", infilename);
            128         exit(1);
            129     }
            130 
            131     ofp = fopen(outfilename, "w+");
            132     //如果不能創建kernel.map文件
            133     if (NULL == ofp)
            134     {
            135         fprintf(stderr, "cannot create the file \"%s\".\n", outfilename);
            136         exit(1);
            137     }
            138 }
            139 
            140 int main(int argc, char *const *argv)
            141 {
            142     int pht_offset, n, i;
            143     Elf32_Ehdr elf_header;//保存elf文件頭
            144     Elf32_Phdr p_header_buf;
            145     Seghdr seg_header_buf;
            146     unsigned short loadable_seg_num = 0;
            147 
            148     init();
            149     proc_opt(argc, argv);
            150     open_file();
            151 
            152     //讀出ELF文件頭
            153     n = fread((void *)&elf_header, ELFHDR_LEN, 1, ifp);
            154 
            155     if (n < 1)
            156     {
            157         fprintf(stderr, "cannot read the \"%s\" file's ELF header!\n", infilename);
            158         die();
            159     }
            160 
            161     //輸出文件的文件頭格式為
            162     //0  1  2  3  4  5  6  7  8  9  10  11(以字節為單位)
            163     //k  e  r  n  e  l  |入口地址|  |段數|
            164     n = fwrite("kernel"61, ofp);
            165 
            166     if (n < 1)
            167     {
            168         fprintf(stderr, "cannot write into \"%s\".\n", outfilename);
            169         die();
            170     }
            171 
            172     //entry address
            173     n = fwrite((void *)(&(elf_header.e_entry)), 41, ofp);
            174 
            175     if (n < 1)
            176     {
            177         fprintf(stderr, "cannot write into \"%s\".\n", outfilename);
            178         die();
            179     }
            180 
            181     fprintf(stdout, "entry address: %x\n", elf_header.e_entry);
            182     //the number of segments
            183     n = fwrite("  "21, ofp);
            184 
            185     if (n < 1)
            186     {
            187         fprintf(stderr, "cannot write into \"%s\".\n", outfilename);
            188         die();
            189     }
            190 
            191     //判斷輸入文件是否是ELF格式文件
            192     //ELF格式的文件頭部的前四字節是“.ELF”的ascii碼
            193     if (((int *)(elf_header.e_ident))[0]!= 0x464c457f)
            194     {
            195         fprintf(stderr, "\"%s\" is not an ELF file!\n", infilename);
            196         die();
            197     }
            198 
            199     //判斷文件是否是可執行文件
            200     if (elf_header.e_type != 2)
            201     {
            202         fprintf(stderr, "\"%s\" is not an excutable file!\n", infilename);
            203         die();
            204     }
            205 
            206     //該ELF支持的機器架構是否是80386類型
            207     if (elf_header.e_machine != 3)
            208     {
            209         fprintf(stderr, "\"%s\" is not for I386!\n", infilename);
            210         die();
            211     }
            212 
            213     //輸出內核文件包含的程序段信息
            214     fprintf(stdout, "\"%s\"含有的程序段的段數: %d\n", infilename, elf_header.e_phnum);
            215 
            216     for (i = 0; i < elf_header.e_phnum; ++i)
            217     {
            218         if (PHDR_LEN != elf_header.e_phentsize)
            219         {
            220             fprintf(stderr, "program header entry is confused!\n");
            221             die();
            222         }
            223 
            224         fseek(ifp, elf_header.e_phoff + i * elf_header.e_phentsize, SEEK_SET);
            225         n = fread(&p_header_buf, elf_header.e_phentsize, 1, ifp);
            226 
            227         if (n < 1)
            228         {
            229             fprintf(stderr, "cannot read the program header entry!\n");
            230             die();
            231         }
            232 
            233         fprintf(stdout, "第%d個段的段頭內容:\n", i + 1);
            234         fprintf(stdout, "\tp_type:   0x%x\n", p_header_buf.p_type);
            235         fprintf(stdout, "\tp_offset: 0x%x\n", p_header_buf.p_offset);
            236         fprintf(stdout, "\tp_vaddr:  0x%x\n", p_header_buf.p_vaddr);
            237         fprintf(stdout, "\tp_paddr:  0x%x\n", p_header_buf.p_paddr);
            238         fprintf(stdout, "\tp_filesz: 0x%x\n", p_header_buf.p_filesz);
            239         fprintf(stdout, "\tp_memsz:  0x%x\n", p_header_buf.p_memsz);
            240         fprintf(stdout, "\tp_flags:  0x%x\n", p_header_buf.p_flags);
            241         fprintf(stdout, "\tp_align:  0x%x\n", p_header_buf.p_align);
            242 
            243         if (1 != p_header_buf.p_type)//is not PT_LOAD
            244         {
            245             fprintf(stderr, "this segment is not loadable\n");
            246             continue;
            247         }
            248 
            249         loadable_seg_num++;
            250         //對每個程序段都在頭部加上描述該程序段的信息頭
            251         //包含程序段的長度以及程序段加載到內存時的虛擬地址
            252         seg_header_buf.memsz = p_header_buf.p_filesz;
            253         seg_header_buf.vaddr = p_header_buf.p_vaddr;
            254 
            255         n = fwrite((void *)&seg_header_buf, SEGHDR_LEN, 1, ofp);
            256         if (1 != n)
            257         {
            258             fprintf(stderr, "cannot write the segment length into \"%s\".\n", outfilename);
            259             die();
            260         }
            261 
            262         //將段內容寫進輸出文件中
            263         fseek(ifp, p_header_buf.p_offset, SEEK_SET);
            264 
            265         while (p_header_buf.p_filesz > MAX_BUF_LEN)
            266         {
            267             n = fread(buffer, 1, MAX_BUF_LEN, ifp);
            268 
            269             if (MAX_BUF_LEN != n)
            270             {
            271                 fprintf(stderr, "cannot read the segment from \"%s\".\n", infilename);
            272                 die();
            273             }
            274 
            275             p_header_buf.p_filesz -= MAX_BUF_LEN;
            276             n = fwrite(buffer, MAX_BUF_LEN, 1, ofp);
            277 
            278             if (1 != n)
            279             {
            280                 fprintf(stderr, "cannot write the segment into \"%s\".\n", outfilename);
            281                 die();
            282             }
            283         }
            284 
            285         if (p_header_buf.p_filesz > 0)
            286         {
            287             n = fread(buffer, p_header_buf.p_filesz, 1, ifp);
            288 
            289             if (1 != n)
            290             {
            291                 fprintf(stderr, "cannot read the segment from \"%s\".\n", infilename);
            292                 die();
            293             }
            294 
            295             n = fwrite(buffer, p_header_buf.p_filesz, 1, ofp);
            296 
            297             if (1 != n)
            298             {
            299                 fprintf(stderr, "cannot write the segment into \"%s\".\n", outfilename);
            300                 die();
            301             }
            302         }
            303     }
            304 
            305     //將輸入文件中可加載段的段數寫進輸出文件頭中
            306     fseek(ofp, 10, SEEK_SET);
            307     n = fwrite((void *)&loadable_seg_num, 21, ofp);
            308 
            309     if (1 != n)
            310     {
            311         fprintf(stderr, "cannot write the entry address into the \"kernel.map\" file!\n");
            312         die();
            313     }
            314 
            315     fclose(ifp);
            316     fclose(ofp);
            317     return 0;
            318 }

            先看看ELF格式文件的組織形式吧:

            整個ELF文件中固定的部分只有ELF頭,它表征整個ELF文件的組織形式。其他的包括程序頭和節頭都不是固定的,甚至可以不包括。程序頭和節頭分別是從文件執行角度和文件鏈接角度來看的。因為我們只關心如何將ELF加載進內存,因此我們只關心程序頭。每個程序頭包括表征一個程序是否可執行以及在文件中的位置和加載到內存中時的起始虛擬地址等信息。我們需要的就是這個信息。
            再看看我們想生成的map文件的組織格式:

            可見文件格式還是相當簡單的,因為我們的目的就是讓lorder可以非常輕松的將文件加載進內存指定位置。
            紅色區域為頭部,指定Magic Number:“kernel”,占6字節,之后是內核的入口地址,再然后是可加載程序段的段數。
            之后每個可加載程序段都有一個段頭,該段頭指定段的大小和段在內存中的起始虛擬地址。
            我們的程序核心目的就是將原始的ELF格式內核文件轉變成我們定義的簡單的map文件,以供loader加載。
            posted on 2011-11-20 14:35 myjfm 閱讀(456) 評論(0)  編輯 收藏 引用 所屬分類: 操作系統
            亚洲国产精品一区二区三区久久| 天天综合久久久网| 国产亚洲美女精品久久久2020| yy6080久久| 97久久精品人人澡人人爽| 精品久久人人爽天天玩人人妻| 伊人久久无码精品中文字幕| 伊人久久大香线焦AV综合影院 | 久久97精品久久久久久久不卡| 国内精品久久久久久久涩爱| 久久99热这里只有精品国产| 93精91精品国产综合久久香蕉| 亚洲乱码中文字幕久久孕妇黑人| 99久久99久久精品国产| 久久精品aⅴ无码中文字字幕不卡 久久精品aⅴ无码中文字字幕重口 | 久久97精品久久久久久久不卡| 久久久WWW成人| 久久久久99精品成人片试看| 久久综合色区| 久久国产精品久久国产精品| 久久久无码精品亚洲日韩京东传媒| 国产成人综合久久综合| 精品久久久久久中文字幕大豆网| 国产精品亚洲美女久久久| 久久九九精品99国产精品| 欧美激情精品久久久久久久九九九 | 亚洲精品无码久久毛片| 国产福利电影一区二区三区久久久久成人精品综合 | 久久综合亚洲欧美成人| 中文精品99久久国产| 精品国产91久久久久久久a| 国产午夜福利精品久久2021| 狠狠色噜噜色狠狠狠综合久久| 香蕉久久AⅤ一区二区三区| 久久精品无码一区二区三区日韩| 成人妇女免费播放久久久| 精品久久久久久久无码 | 韩国免费A级毛片久久| 亚洲色大成网站www久久九 | 久久九九免费高清视频| 久久久久久国产a免费观看不卡 |