2009年12月14日星期一

通过IPv6方式访问blogspot的方法

既然GFW短期之内还不会延伸到IPv6上,而GFW对blogspot的封禁看来会一直持续下去,这里给出一个通过IPv6访问blogspot的方法:
在你已经通了IPv6的情况下,其实很简单:在上blogspot的时候,把代理设为ipv6.google.com,端口为80,协议为HTTP。
当然,总是改代理很麻烦。因此可以用各种插件来达到自动切换代理,比如我用的FoxyProxy:
装好之后,在选项里,新建代理服务器,在第二页输入ipv6.google.com和80,在第三页新增URL模板,名字随便起,URL模板写*blogspot.com*,选白名单/通配符,确定,就可以了。也可以再加一个模板,*blogger.com*。
假如大家都会用这个办法了,那原来的Live Space就可以考虑不更新了……

2009年11月19日星期四

利用 bcdedit 解决 Vista 启动问题

前一段时间,把系统原来的还原分区(一个NTFS)清了,在那里装了FreeBSD 8/amd64。之后发现,FreeBSD的分区引导记录很不行,他只找活动分区启动,而不管自己是哪个分区的引导记录(大概也不知道……),所以从原来的BSD切换到新装的很麻烦,要手动改活动分区。于是就装了个grub4dos,折腾了半天终于好了。装完之后,尝试新菜单,发现Vista进不去了…… 提示大概是这样的:\Windows\system32\winload.exe 文件未找到或者已损坏 错误0xc000000e。试了一下,发现Vista启动菜单里面其他的项目也用不了了。
想了一下,多半是干掉那个还原分区之后,Windows所在的分区成了第一个Windows能够认出来的分区,于是这个Boot Loader分不清楚了,不能在老地方找到这个文件了……
先尝试把那个新装了BSD的分区类型改成NTFS,结果Windows还是不认…… 改回去之后,我想只好手动修改启动数据库了。Vista的启动数据库,不像XP就是根目录下面有一个boot.ini,而是在根目录下面\Boot\BCD这个文件里面,还是个二进制文件…… Windows就给了一个bcdedit来弄。
因为进不了Vista,我尝试着用虚拟机里的XP来跑。这个虚拟机同时也把主机的真实硬盘作为第二块硬盘挂在上面。
启动虚拟机,尝试了一下,bcdedit竟然能用,于是拷到WinXP这边来。主机Vista所在的盘在虚拟机里面是D盘,所以在运行bcdedit的时候,后面都要加上/store d:\boot\BCD 。
改的过程其实很少。bcdedit原来那些命令也都能用。
命令里面某一项的GUID,可以通过直接运行 bcdedit /store d:\boot\BCD 来了解,最上面{xxxxxxxx-.....}那个就是了,一串很长的十六进制数。默认项这个可以用{default}代替。
首先,把默认项指定成Vista(原来是老BSD):
bcdedit /store d:\boot\BCD /default <Vista项的GUID>
然后设置默认项设备为分区d(一开始我设了c,结果还是不行…… Windows还是把那个算进去了么……)
bcdedit /store d:\boot\BCD /set {default} device partition=D:
bcdedit /store d:\boot\BCD /set {default} osdevice partition=D:
这就好了。
效果不用重启都能看见。还是利用虚拟机,qemu或者VirtualBox都可以,直接挂主机硬盘,Vista果然跑起来了…… 不过一会儿就蓝屏了……

2009年9月17日星期四

WordPress 多层菜单

下了个主题,发现只支持一级菜单……
去网上,先找了一个Multi-level Navigation插件,但是主题不配合……
继续找,找到那么一篇文章:
WordPress Multi-Level Drop Down menu using jQuery | SEOAdsenseThemes.com
弄到WP里面去,竟然就好了……
其实就是加:
<script type='text/javascript'>
jQuery(document).ready(function() {
jQuery("#dropmenu ul").css({display: "none"}); // Opera Fix
jQuery("#dropmenu li").hover(function(){
jQuery(this).find('ul:first').css({visibility: "visible",display: "none"}).show(268);
},function(){
jQuery(this).find('ul:first').css({visibility: "hidden"});
});
});

</script>
<style type="text/css">
#dropmenu, #dropmenu ul {list-style-type:none; list-style-position:outside; position:relative;z-index:300; width:100%;}
</style>
到HTML页面的head部分里面,然后把原来的
<?php wp_list_pages('title_li=&depth=10'); ?>
换成
<ul id="dropmenu">
<?php wp_list_pages('sort_column=menu_order&title_li='); ?>
</ul>
就行了……

2009年6月2日星期二

gdb的出错消息

一直以来,运行gdb,之后输入 attach <PID>,会收到一些错误消息:
> gdb
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd".
(gdb) attach 7590
Attaching to process 7590
/usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/solib-svr4.c:1443: internal-error: legacy_fetch_link_map_offsets called without legacy link_map support enabled.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) n

/usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/solib-svr4.c:1443: internal-error: legacy_fetch_link_map_offsets called without legacy link_map support enabled.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Create a core file of GDB? (y or n) n
Reading symbols from /usr/local/kde4/bin/dolphin...(no debugging symbols found)...done.
....
Loaded symbols for /usr/local/kde4/lib/libkfontinst.so.5
Reading symbols from /libexec/ld-elf.so.1...done.
Loaded symbols for /libexec/ld-elf.so.1
[Switching to Thread 0x2dd6b260 (LWP 100239)]
0x29be3243 in select () from /lib/libc.so.7
(gdb)
一直也不知道是什么道理…… 今天去网上查,终于看见一个说法:
需要attach的话,只能运行 gdb -p <PID> <exec file>
也就是说,要提供原来的可执行文件,才能attach到一个现有process……
我试了一下,的确好了:
> gdb -p 7590 /usr/local/kde4/bin/dolphin
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd"...(no debugging symbols found)...
Attaching to program: /usr/local/kde4/bin/dolphin, process 7590
Reading symbols from /usr/local/kde4/lib/libkio.so.7...(no debugging symbols found)...done.
Loaded symbols for /usr/local/kde4/lib/libkio.so.7
......
Reading symbols from /libexec/ld-elf.so.1...done.
Loaded symbols for /libexec/ld-elf.so.1
[Switching to Thread 0x2dd6b260 (LWP 100239)]
0x29be3243 in select () from /lib/libc.so.7
(gdb)
貌似这个问题,在GDB里面很早就修正了。FreeBSD随系统自带的GDB还是6.1.1,ports里倒是提供了一个6.6,但是不支持调试多线程的程序…… 不知道啥时候这个事情能够解决……

2009年4月19日星期日

Joomla 热门新闻的有效期

     热门文章上的内容,是完全按照新闻点击次数排的。虽然原来发布的时候有个失效时间,但是大部分人懒得写,导致很旧的但是点击量大的新闻会长时间排在顶上,违背了新闻和热门的意思。
     因为这个原因,我想说不定能够设置一下,比如只显示两个月的新闻。但是看了一下那个热门新闻模块(mod_mostread),设置很简单,没这方面内容。
     于是只好改代码了么…… 打开/joomla/modules/mod_mostread.php,看见如下代码:
  • case 1:
  • default:
  • //Content Items only
  • $query = "SELECT a.id, a.title, a.sectionid, a.catid"
  • . "\n FROM #__content AS a"
  • . "\n LEFT JOIN #__content_frontpage AS f ON f.content_id = a.id"
  • . "\n INNER JOIN #__categories AS cc ON cc.id = a.catid"
  • . "\n INNER JOIN #__sections AS s ON s.id = a.sectionid"
  • . "\n WHERE ( a.state = 1 AND a.sectionid > 0 )"
  • . "\n AND ( a.publish_up = '$nullDate' OR a.publish_up <= '$now' )"
  • . "\n AND ( a.publish_down = '$nullDate' OR a.publish_down >= '$now' )"
  • . ( $access ? "\n AND a.access <= $my->gid AND cc.access <= $my->gid AND s.access <= $my->gid" : '' )
  • . ( $catid ? "\n AND ( a.catid IN ( $catid ) )" : '' )
  • . ( $secid ? "\n AND ( a.sectionid IN ( $secid ) )" : '' )
  • . ( $show_front == "0" ? "\n AND f.content_id IS NULL" : '' )
  • . "\n AND s.published = 1"
  • . "\n AND cc.published = 1"
  • . "\n ORDER BY a.hits DESC"
  • ;

  • 那个case 1对应选项里的“只显示内容项目”,下面明显在构造SQL查询语句。<br />搜了一下,MySQL有个函数,DATEDIFF(),返回两个日期差的天数,这不是正好么。<br />在其中插入一句判断:
  • . "\n AND ( DATEDIFF('$now', a.created) <= 60 )"
  • 于是问题解决~ 这种脚本语言还真是容易学容易用……

    2009年4月1日星期三

    FireBoard的登录跳转

    最近在一个Joomla上架论坛,用着FireBoard。这个东西有个毛病,就是登录之后跳转到主页,而不是到论坛,看着很不行。
    为了解决这个问题,回去看代码。FireBoard那个登录链接在template/default/plugin/profilebox/profilebox.php里面生成的,原来是这样:

    $loginlink = sefRelToAbs('index.php?option=com_login&amp;Itemid=' . $Itemid));

    我想先把返回地址传过去。于是改成:

    $loginlink = sefRelToAbs('index.php?option=com_login&amp;Itemid=' . $Itemid . "&return=" . sefRelToAbs('index.php?option=com_fireboard'));

    接下来看看/joomla/components/com_login/login.html.php:

    $return = $params->get('login');

    以及:

    <form action="<?php echo sefRelToAbs( 'index.php?option=login' ); ?>" method="post" name="login" id="login">

    看来是转到index.php进行登录工作。再看看index.php:
  • // frontend login & logout controls
  • $return = strval( mosGetParam( $_POST, 'return'));
  • $message = intval( mosGetParam( $_POST, 'message', 0 ) );
  • if ($option == 'login') {
  • $a = $return;
  • $mainframe->login();
  • $return = $a;
  • // JS Popup message
  • ......
  •  
  • if ( $return && !( strpos( $return, 'com_registration' ) || strpos( $return, 'com_login' ) ) ) {
  • // checks for the presence of a return url
  • // and ensures that this url is not the registration or login pages
  • mosRedirect( $return );
  • } else {
  • mosRedirect( $mosConfig_live_site .'/index.php' );
  • }
  •  
  • 看来原来就有跳转的代码。这样就好办了。
    我原来尝试在那个login链接后面加&return=xxx,但是试了一个晚上,一点用都没有。
    后来才发现,貌似是那个$return的变量在起作用。
    最后,修改com_login/login.html.php:
    把原来的$return=xxx改成:

    $return_old = $params->get('login');
  • $return = strval(mosGetParam($_REQUEST, 'return', $return_old));

  • 终于,问题解决,FireBoard登录之后,又跳转回FireBoard了~
    其实看原来那个$return=$param->get啥的,应该是有更好的办法的,但是这样也挺通用的,就行了吧……

    2009年3月10日星期二

    新的键盘 & usbhidaction

    从同学那边借了一个键盘用,反正他有好几个键盘,这个放在旁边也不用。型号是 Microsoft Natural Ergonomic Keyboard 4000,很大的一个键盘,还是人体工程学设计的。
    装载ukbd和uhid模块,插上键盘,显示出来两个设备: ukbd0 和 uhid0。
    貌似ukbd0马上就被Xorg接受了,插上后按键就能够被Xorg接收到。
    而那个uhid0,貌似就是用来发送特殊键的了。这个键盘上有不少特殊键,比如一对滚轮一样的Zoom键,Back/Forward, 控制音量和播放器的,启动程序的,以及可以自定义的特殊键。
    研究了一下,有两个现成的工具。usbhidctl能够接受并显示 uhid 设备发过来的信息,而 usbhidaction 能够根据预先指定的配置文件,在接收到 uhid 设备的时候,执行对应的程序。
    其实 FreeBSD 自带的 usbhidctl 和 usbhidaction 都有问题,他们对于 Report ID 这个HID设备的参数没有处理好。
    一个HID设备允许其上的各个组件利用同一个接口发送信息,而这些信息就通过 Report ID 区分。在信息格式描述符中提到 Report ID 的设备,在发出来的数据包的前面会多一个字节,就是这个数据包所属部分的Report ID。
    usbhidaction没有处理这个多出来的字节,导致它每次都少收一个字节,然后再收一个一字节的包…… 改了就好了。但是这个修改其实涉及到libusbhid,因此光修改usbhidaction还不行。但是要把这整个需要修改的地方做成patch提交,还要花一些功夫。
    于是我改了一下 usbhidaction 和 usbhidctl,还有libusbhid,临时把 Report ID 指定为1,并且根据描述符的处理结果决定接受的字节数。原来的 usbhidaction 默认的 Report ID 是用一个ioctl获取的,这个令我难以理解…… 不是可以有不止一个么…… 关于这个,我发了封信给freebsd-stable,但是没人回…… 看来还是需要完整的patch才比较容易得到接受。
    顺便贴一下我现在用的 usbhidaction 的配置文件。我改了devd.conf使得插入键盘的时候自动运行之,效果还是不错的。
     1 # Volume Control: Up, Down & Mute
     2 Consumer:Unassigned     233  0   /usr/sbin/mixer vol +3
     3 Consumer:Unassigned     234  0   /usr/sbin/mixer vol -3
     4 Consumer:Unassigned     226  0   /usr/sbin/mixer vol 0
     5 # Pause or Play
     6 Consumer:Unassigned     205  0   /usr/local/bin/mpc toggle &
     7 #                                alt+F11
     8
     9 # Calculator
    10 Consumer:Unassigned     402  0   su henryhu -c "/usr/bin/env DISPLAY=:0 tiemu &"
    11
    12 # Back & Forward
    13 Consumer:Unassigned     548  0   su henryhu -c "/usr/bin/env DISPLAY=:0 /usr/local/bin/xdotool key alt+Left"
    14 Consumer:Unassigned     549  0   su henryhu -c "/usr/bin/env DISPLAY=:0 /usr/local/bin/xdotool key alt+Right"
    15
    16 # Zoom Up & Down
    17 Consumer:Unassigned     557  0   su henryhu -c "/usr/bin/env DISPLAY=:0 /usr/local/bin/xdotool click 4"
    18 Consumer:Unassigned     558  0   su henryhu -c "/usr/bin/env DISPLAY=:0 /usr/local/bin/xdotool click 5"
    19
    20 # 1 .. 5
    21 Consumer:Consumer_Control.Microsoft:0xff05  1   0   su henryhu -c "/usr/bin/env DISPLAY=:0 /usr/local/bin/xdotool key ctrl+Up"
    22 Consumer:Consumer_Control.Microsoft:0xff05  2   0   su henryhu -c "/usr/bin/env DISPLAY=:0 /usr/local/bin/xdotool key ctrl+a 1"
    23 Consumer:Consumer_Control.Microsoft:0xff05  4   0   su henryhu -c "/usr/bin/env DISPLAY=:0 /usr/local/bin/xdotool key ctrl+a 2"
    24 Consumer:Consumer_Control.Microsoft:0xff05  8   0   su henryhu -c "/usr/bin/env DISPLAY=:0 /usr/local/bin/xdotool key ctrl+a 3"
    25 Consumer:Consumer_Control.Microsoft:0xff05  16  0   su henryhu -c "/usr/bin/env DISPLAY=:0 /usr/local/bin/xdotool key ctrl+Down"
    26
    27 # My Favorites
    28 Consumer:Unassigned     386  0   su henryhu -c "/usr/bin/env DISPLAY=:0 /usr/local/bin/xscreensaver-command -lock"
    29 #/usr/local/bin/sudo -u henryhu /usr/local/bin/xdotool key ctrl+alt+l >& /var/log/xdotool.log
    30
    31 # Web/Home, Search & Mail
    32 Consumer:Unassigned     547  0   su henryhu -c "/usr/bin/env DISPLAY=:0 firefix &"
    33 Consumer:Unassigned     545  0   su henryhu -c "/usr/bin/env DISPLAY=:0 firefox http://www.google.com &"
    34 Consumer:Unassigned     394  0   su henryhu -c "/usr/bin/env DISPLAY=:0 firefox http://www.gmail.com &"
    35


    2009年2月25日星期三

    英语46级查分的程序

    昨天46级能够查分了,研究了一下……
    主页面调用了一段javascript,验证码竟然是本地验证的…… 这个不说,其实最后查分就是通过XMLHttpRequest直接查…… 就没什么加密一类的事情……
    之后找了一下,好像XMLHttpRequest这个东西还只有Javascript里面才有,python用起来还不方便…… 用FireBug试了一下,因为这个查分系统的请求里面没有数据,所以这个请求其实很简单,拿urllib糊弄一下就好了……
    另外关于FireFox里面不能查的问题,貌似是FireFox的XMLHttpRequest在send(null)的时候HTTP头里面没有Content Length字段,其实send("")就可以了……
    另外,最后这个系统还检查一下Referer,至少不是什么都不干……


     1 import urllib
     2 import urllib2
     3
     4 id = "Your ID"
     5 t = "4"
     6 url = 'http://cet.99sushe.com/cetscore_99sushe0902.html?t=' + t + '&id=' + id
     7 values = {}
     8 headers = { "Referer" : "http://cet.99sushe.com" }
     9
    10 data = urllib.urlencode(values)
    11 req = urllib2.Request(url, data, headers)
    12 response = urllib2.urlopen(req)
    13 the_page = response.read()
    14 result = the_page.split(',')
    15
    16 print "Listening :",result[0]
    17 print "Reading   :",result[1]
    18 print "Mixed     :",result[2]
    19 print "Writing   :",result[3]
    20 print "Total     :",result[4]
    21 print "School    :",result[5].decode('gb2312')
    22 print "Your Name :",result[6].decode('gb2312')
    23 print "Name1     :",result[7].decode('gb2312')
    24 print "Name2     :",result[8].decode('gb2312')
    25 print "Name3     :",result[9].decode('gb2312')

    2009年1月29日星期四

    关于A20地址线的那些事情

    从前在BIOS里面见过关于A20地址线的选项,后来启动FreeDOS什么的时候好像也见过A20的事情,一直不知道是干嘛的……
    后来某天看BSD loader代码的时候,看见启用A20地址线的事情…… 于是去wiki上查了一下,原来是这么回事……
    8086那个时候,地址线只有20位,叫做A0~A19,也就是没有A20地址线的。2^20=1M,因此那时能够访问的内存范围是1M。
    那个时候也分段,地址由段寄存器左移4位,加上基地址,得到物理地址。
    段寄存器和基地址都是16位的,这样就能够访问20位的空间了。但是有个问题……
    段寄存器最大FFFF,基地址也是。所以地址最大是FFFF:FFFF,但是FFFF左移四位得到FFFF0,加上FFFF,得到10FFEF,也就是FFFFF+FFF0。但是物理内存只有1M,最大物理地址范围应该是0~FFFFF,因此多了FFF0,超出了物理地址范围。
    这样,访问到超出范围的时候,8086会自动做一个处理,把高位的1删掉,也就是10xxxx->xxxx,然后返回对应位置。

    按理来说,这是个bug,8086应该返回个错误啥的。但是,既然这已经是事实了,有的程序就开始用这一点,来访问0~FFEF的内存范围,差不多是前64K少一些的范围。这就为日后的新CPU出了难题……

    80286,80386等等更NX的处理器出现了,他们支持访问更大的内存范围。自然,10xxxx和xxxx也就指向了不同的地方。但是,跑那些用到从前bug的老程序的时候,就出问题了…… 改了10xxxx的xxxx不变,导致乱七八糟的问题……
    IBM他们就脑残了一下,说,我们在A20地址线(也就是那个1的位置……)装个开关吧~ 然后又脑残一下,看见键盘控制器正好有一根线空着,就说,我们让键盘控制器来管这个开关吧~
    于是,著名的Gate A20就这么产生了……
    打开:输出0xd1到0x64端口,等8042(键盘控制器)空了,再输出0xdf到0x60端口

    保护模式的操作系统,自然都需要访问1M以上的内存,而且不希望某一位地址一直是0。所以保护模式的操作系统启动步骤之一,就是打开A20。
    但是,IBM那些人们没想到,日后有些环境需要频繁切换A20端口,而键盘控制器是如此之慢…… 他们当初认为,这个切换发生频率很低,因此慢一点没关系……

    于是就有了Fast Gate A20的事情。利用0x92端口,读入之后,把第二位改成1,然后写回去,能快一点。
    但这个引起了新的bug。毕竟只有某些系统支持0x92端口的这个用发,而有些系统…… 改了0x92会导致没有显示之类的,所以有危险……
    后来么,intel也不爽了,就搞了个0xee端口,读打开A20,写关闭…… 速度比从前更快了……

    于是,这样就有了3中方法,由慢到快。某些程序就一个一个试,试了一个验证一下。
    但是,缓存又来捣乱。有的系统虽然开了A20,还是会把几个字节缓存起来,10xxxx和xxxx一样……

    总的来说,A20就是个麻烦的事情,当初搞个BIOS调用之类的也就over了么…… 不过现在的新的系统,基本上都没有A20的问题了,虽然打开A20还是系统启动的必要步骤之一……
    参见A20 - a pain from the past

    2009年1月27日星期二

    80x86 保护模式 内存访问 学习总结

    话说这个80286搞出来的保护模式,又是分段又是分页,从前没好好研究过,从来就没有搞清楚过……
    家里翻到一本老教材,《微型计算机技术及应用——从16位到32位》,里面讲80386的章节,终于基本上讲清楚了……
    假设现在是即分段又分页的情况……

    首先,程序里面引用一个地址,其实指的都是逻辑地址。这样的引用需要两部分数据:段选择子以及段内偏移量。
    然后么,段选择子基本上就放在老的段寄存器里面,不过现在是起一个索引的作用。
    段选择子其实分几部分。总共16位,前13位是个索引,接下来1位指定是到LDT还是GDT里面找。最后两位是特权级。
    LDT和GDT,一个是局部描述符表,一个是全局描述符表,反正是两张表,存了一大堆的段描述符。表的位置放在LDTR和GDTR两个寄存器里面。
    现在研究内存访问,所以只讨论存储段描述符,每个8个字节,包括了段的开始地址(32位)、界限(20位),还有一堆标志什么的。
    用前面那个索引,从LDT或GDT里面找到描述符,然后就有了段基地址。之前需要检查偏移量符合界限,以及其他各种权限之类的检查。
    最后加上偏移量,我们就得到了线性地址~ 分段部分完成~

    然后,线性地址有32位。把它分为3段:10位,10位,12位。
    系统有一堆控制寄存器,其中,CR3里面,保存着页目录的基地址。
    页目录也是一个表,每项4个字节,每个里面都有一个页表基地址…… 当然还有一堆别的东西,什么权限、标志之类的……
    线性地址的第一段,10位,就是这个表的索引。把它乘以4(每项4个字节么……),加上CR3里面的基地址,就有了页表的基地址……
    页表的结构也差不多,也是4个字节一项。用线性地址第二段,10位,乘以4,加上页表基地址,就有了页基地址……
    最后,拿第三段,12位,加上业基地址,终于…… 我们得到了物理地址!

    接下来么,做一些数学计算。
    页内偏移量(线性地址第三段)有12位,2^12=4*1k=4k,和一页大小为4k吻合~
    线性地址前两段,每段10位,对应的表可以有1k项。所以,经过这两级,可以索引1M个页。每个页4k那么大,所以…… 总共4G。
    其实这个计算很NC对吧…… 总共32位,没有1位浪费,全都用来索引的情况下,当然可以索引2^32=4G……
    然后,一个页表有多大呢?一项4字节,共1024字节,所以一个页表4k大。总共1k个页表,所以页表总共占4M那么多地方。
    页目录表么,就4k大啦,比起页表也不算什么……
    然后,段的界限只有20位,2^20=1M,难道一个段只有1M那么大?其实剩下的标志里面有一个粒度位G,能够指定界限以1字节还是4k为单位。
    以4k为单位的时候,就能有1M*4k=4G那么大的段,这个就很完美了么~
    段选择子有16位,因此最多有2^16=65536个段,真多……

    然后,这样n级转换不是很慢么,所以系统里还有转换缓冲区。貌似这个区操作系统还可以控制,让哪些转换结果留在缓冲里面,这样下次碰见一个逻辑地址就不用多级转换了……
    另外,程序用到段选择子的时候,必然都在6个段寄存器里。所以,每次把东西扔到段寄存器里面去,CPU就把对应的段描述符装到一个隐藏的寄存器里面,这样,大部分时间就不用去查LDT/GDT之类的了……