這篇博文,我們編寫一個C語言的小程序,來解析數據段或者代碼段描述符的各個字段。這樣我們閱讀原書的代碼就會方便一點,只要運行這個小程序,就可以明白程序中定義的數據段或者代碼段的描述符了。
這段代碼,我用了“位字段”的知識,這還是第一次使用C語言的這個特性呢,如果有不對的地方,歡迎博友斧正。
寫代碼之前,我們再復習一下數據段描述符和代碼段描述符的格式。(圖片選自趙炯老師的《Linux內核完全剖析》)

?
~~~
#include <stdio.h>
//定義描述符中的低32位
struct seg_des_low_word
{
unsigned int limit_0_15:16;
unsigned int base_0_15 :16;
};
~~~
~~~
//定義描述符中的高32位
struct seg_des_high_word
{
unsigned int base_16_23 :8;
unsigned int type :4;
unsigned int s :1;
unsigned int dpl :2;
unsigned int p :1;
unsigned int limit_16_19:4;
unsigned int avl :1;
unsigned int l :1;
unsigned int d_b :1;
unsigned int g :1;
unsigned int base_24_31 :8;
};
~~~
~~~
//對TYPE字段進行解析
void parse_type(unsigned int t)
{
if(t<=7)
printf("數據段: ");
else
printf("代碼段: ");
switch(t)
{
case 0:
case 1:
printf("只讀\n");
break;
case 2:
case 3:
printf("可讀可寫\n");
break;
case 4:
case 5:
printf("向下擴展,只讀\n");
break;
case 6:
case 7:
printf("向下擴展,可讀可寫\n");
break;
case 8:
case 9:
printf("僅執行\n");
break;
case 10:
case 11:
printf("可讀,可執行\n");
break;
case 12:
case 13:
printf("一致性段,僅執行\n");
break;
case 14:
case 15:
printf("一致性段,可讀,可執行\n");
break;
default:
break;
}
}
void parse_seg_des(struct seg_des_low_word* pl, struct seg_des_high_word* ph)
{
unsigned int seg_base;
//拼接基地址字段
~~~
~~~
seg_base = (ph->base_24_31<<24)|(ph->base_16_23<<16)|pl->base_0_15;
printf("seg_base = %#X\n",seg_base);
unsigned int seg_limit;
//拼接段限長字段
~~~
~~~
seg_limit = (ph->limit_16_19<<16)|pl->limit_0_15;
printf("seg_limit = %#X\n",seg_limit);
//下面的字段輸出是不是很方便?這就是位字段的好處之一
~~~
~~~
printf("S = %d\n",ph->s);
printf("DPL = %d\n",ph->dpl);
printf("G = %d\n",ph->g);
printf("D/B = %d\n",ph->d_b);
printf("TYPE = %d\n",ph->type);
~~~
~~~
//解析TYPE(目前只支持數據段描述符和代碼段描述符,其他類型的,可以自己擴充)
parse_type(ph->type);
}
int main(void)
{
printf("please input the segment descriptor, low= high=\n");
struct seg_des_high_word *high;
struct seg_des_low_word *low;
unsigned int l_word = 0;
unsigned int h_word = 0;
//請求用戶輸入描述符,先是低32位,再是高32位
~~~
~~~
scanf("%x" "%x",&l_word,&h_word);
printf("-----------------------\n");
high =(struct seg_des_high_word*)&h_word;
low =(struct seg_des_low_word*)&l_word;
parse_seg_des(low,high);
printf("------------------------\n");
return 0;
}
~~~
好了,代碼就是這樣。下面看看結果吧。編譯后并運行。提示我們輸入:

我們就輸入原書的配書代碼c11_mbr.asm中
~~~
;創建#1描述符,保護模式下的代碼段描述符
mov dword [bx+0x08],0x7c0001ff
mov dword [bx+0x0c],0x00409800
~~~
注意,輸入格式是16進制(不需要前導的0x),先輸入低32位,也就是7c0001ff,然后空格,再輸入高32位,也就是00409800,最后回車,就出結果了。

效果還不錯吧。哈哈。
(完)