2012年3月26日 星期一

gcc 自製 Library

轉自 PTT LinuxDev

作者: cole945 (躂躂..) 看板: LinuxDev
標題: [心得] 用gcc 自製Library
時間: Sun Nov 5 04:15:45 2006

Library可分成三種,static、shared與dynamically loaded。

1. Static libraries

Static 程式庫用於靜態連結,簡單講是把一堆object檔用ar(archiver)
包裝集合起來,檔名以`.a’ 結尾。優點是執行效能通常會比後兩者快,
而且因為是靜態連結,所以不易發生執行時找不到library或版本錯置而
無法執行的問題。缺點則是檔案較大,維護度較低;例如library如果發
現bug需要更新,那麼就必須重新連結執行檔。

1.1 編譯

編譯方式很簡單,先例用`-c’ 編出object 檔,再用ar 包起來即可。

____ hello.c ____
#include <stdio.h>
void hello(){ printf(“Hello “); }

____ world.c ____
#include <stdio.h>
void world(){ printf(“world.”); }

____ mylib.h ____
void hello();
void world();

$ gcc -c hello.c world.c /* 編出hello.o 與world.o */
$ ar rcs libmylib.a hello.o world.o /* 包成limylib.a */

這樣就可以建出一個檔名為libmylib.a 的檔。輸出的檔名其實沒有硬性規定,
但如果想要配合gcc 的’-l’ 參數來連結,一定要以`lib’ 開頭,中間是你要
的library名稱,然後緊接著`.a’ 結尾。

1.2 使用

____ main.c ____
#include “mylib.h”
int main() {
hello();
world();
}

使用上就像與一般的object 檔連結沒有差別。

$ gcc main.c libmylib.a

也可以配合gcc 的`-l’ 參數使用

$ gcc main.c -L. -lmylib

`[1;33m-L[1;32mdir[m' 參數用來指定要搜尋程式庫的目錄,`.' 表示搜尋現在所在的目錄。
通常預設會搜/usr/lib 或/lib 等目錄。
`[1;33m-l[1;32mlibrary[m' 參數用來指定要連結的程式庫,'mylib' 表示要與mylib進行連結
,他會搜尋library名稱前加`lib'後接`.a'的檔案來連結。

$ ./a.out
Hello world.
2. Shared libraries

Shared library 會在程式執行起始時才被自動載入。因為程式庫與執行檔
是分離的,所以維護彈性較好。有兩點要注意,shared library是在程式起始
時就要被載入,而不是執行中用到才載入,而且在連結階段需要有該程式庫
才能進行連結。

首先有一些名詞要弄懂,soname、real name與linker name。

soname 用來表示是一個特定library 的名稱,像是libmylib.so.1 。
前面以`lib' 開頭,接著是該library 的名稱,然後是`.so' ,接著
是版號,用來表名他的介面;如果介面改變時,就會增加版號來維護相容度。

real name 是實際放有library程式的檔案名稱,後面會再加上minor 版號與
release 版號,像是libmylib.so.1.0.0 。

一般來說,版號的改變規則是(印象中在APress-Difinitive Guide to GCC中有
提到,但目前手邊沒這本書),最尾碼的release版號用於程式內容的修正,
介面完全沒有改變。中間的minor用於有新增加介面,但相舊介面沒改變,所以
與舊版本相容。最前面的version版號用於原介面有移除或改變,與舊版不相容
時。

linker name是用於連結時的名稱,是不含版號的soname ,如: libmylib.so。
通常linker name與real name是用ln 指到對應的real name ,用來提供
彈性與維護性。

2.1 編譯
shared library的製作過程較複雜。

$ gcc -c -fPIC hello.c world.c

編譯時要加上-fPIC 用來產生position-independent code。也可以用-fpic
參數。(不太清楚差異,只知道-fPIC 較通用於不同平台,但產生的code較大
,而且編譯速度較慢)。

$ gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0.0 \
hello.o world.o

-shared 表示要編譯成shared library
-Wl 用於參遞參數給linker,因此-soname與libmylib.so.1會被傳給linker處理。
-soname用來指名soname 為limylib.so.1
library會被輸出成libmylib.so.1.0.0 (也就是real name)

若不指定soname 的話,在編譯結連後的執行檔會以連時的library檔名為
soname,並載入他。否則是載入soname指定的library檔案。

可以利用objdump 來看library 的soname。

$ objdump -p libmylib.so | grep SONAME
SONAME libmylib.so.1

若不指名-soname參數的話,則library不會有這個欄位資料。

在編譯後再用ln 來建立soname 與linker name 兩個檔案。
$ ln -s libmylib.so.1.0.0 libmylib.so
$ ln -s libmylib.so.1.0.0 libmylib.so.1
2.2 使用

與使用static library 同。

$ gcc main.c libmylib.so

以上直接指定與libmylib.so 連結。

或用

$ gcc main.c -L. -lmylib

linker會搜尋libmylib.so 來進行連結。

如果目錄下同時有static與shared library的話,會以shared為主。
使用-static 參數可以避免使用shared連結。

$ gcc main.c -static -L. -lmylib

此時可以用ldd 看編譯出的執行檔與shared程式庫的相依性
$ldd a.out
linux-gate.so.1 => (0xffffe000)
[1;33mlibmylib.so.1 => not found[m
libc.so.6 => /lib/libc.so.6 (0xb7dd6000)
/lib/ld-linux.so.2 (0xb7f07000)
輸出結果顯示出該執行檔需要libmylib.so.1 這個shared library。
會顯示not found 因為沒指定該library所在的目錄,所找不到該library。

因為編譯時有指定-soname參數為libmylib.so.1 的關係,所以該執行檔會
載入libmylib.so.1。否則以libmylib.so連結,執行檔則會變成要求載入
libmylib.so

$ ./a.out
./a.out: error while loading shared libraries: [1;33mlibmylib.so.1[m:
cannot open shared object file: No such file or directory

因為找不到libmylib.so.1 所以無法執行程式。
有幾個方式可以處理。

a. 把libmylib.so.1 安裝到系統的library目錄,如/usr/lib下
b. 設定/etc/ld.so.conf ,加入一個新的library搜尋目錄,並執行ldconfig
更新快取
c. 設定LD_LIBRARY_PATH 環境變數來搜尋library
這個例子是加入目前的目錄來搜尋要載作的library
$ LD_LIBRARY_PATH=. ./a.out
Hello world.
3. Dynamically loaded libraries

Dynamicaaly loaded libraries 才是像windows 所用的DLL ,在使用到
時才載入,編譯連結時不需要相關的library。動態載入庫常被用於像plug-ins
的應用。

3.1 使用方式
動態載入是透過一套dl function來處理。
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
開啟載入filename 指定的library。
void *dlsym(void *handle, const char *symbol);
取得symbol 指定的symbol name在library被載入的記憶體位址。
int dlclose(void *handle);
關閉dlopen開啟的handle。
char *dlerror(void);
傳回最近所發生的錯誤訊息。

____ dltest.c ____
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main() {
void *handle;
void (*f)();
char *error;

/* 開啟之前所撰寫的libmylib.so 程式庫*/
handle = dlopen("./libmylib.so", RTLD_LAZY);
if( !handle ) {
fputs( dlerror(), stderr);
exit(1);
}

/* 取得hello function 的address */
f = dlsym(handle, "hello");
if(( error=dlerror())!=NULL) {
fputs(error, stderr);
exit(1);
}
/* 呼叫該function */
f();
dlclose(handle);
}

編譯時要加上-ldl 參數來與dl library 連結
$ gcc dltest.c -ldl
結果會印出Hello 字串
$ ./a.out
Hello

關於dl的詳細內容請參閱man dlopen

 

benwei的bos

benwei的bos
https://github.com/benwei/bos
以下是bootldr.s

;*********************************************
; bootldr.s
; - Bootloader for loading MYOS.BIN
;
; Modify the source from
; Operating Systems Development Tutorial
;*********************************************
bits 16 ; we are in 16 bit real mode
org 0 ; we will set regisers later
start: jmp main ; jump to start of bootloader
;*********************************************
; BIOS Parameter Block
;*********************************************
; BPB Begins 3 bytes from start. We do a far jump, which is 3 bytes in size.
; If you use a short jump, add a "nop" after it to offset the 3rd byte.
bpbOEM db "My OS "
bpbBytesPerSector: DW 512
bpbSectorsPerCluster: DB 1
bpbReservedSectors: DW 1
bpbNumberOfFATs: DB 2
bpbRootEntries: DW 224
bpbTotalSectors: DW 2880
bpbMedia: DB 0xf0 ;; 0xF1
bpbSectorsPerFAT: DW 9
bpbSectorsPerTrack: DW 18
bpbHeadsPerCylinder: DW 2
bpbHiddenSectors: DD 0
bpbTotalSectorsBig: DD 0
bsDriveNumber: DB 0
bsUnused: DB 0
bsExtBootSignature: DB 0x29
bsSerialNumber: DD 0xa0a1a2a3
bsVolumeLabel: DB "BOS FLOPPY "
bsFileSystem: DB "FAT12 "
;************************************************;
; Prints a string
; DS=>SI: 0 terminated string
;************************************************;
Print:
lodsb ; load next byte from string from SI to AL
or al, al ; Does AL=0?
jz PrintDone ; Yep, null terminator found-bail out
mov ah, 0eh ; Nope-Print the character
int 10h
jmp Print ; Repeat until null terminator found
PrintDone:
ret ; we are done, so return
absoluteSector db 0x00
absoluteHead db 0x00
absoluteTrack db 0x00
;************************************************;
; Convert CHS to LBA
; LBA = (cluster - 2) * sectors per cluster
;************************************************;
ClusterLBA:
          sub ax, 0x0002 ; zero base cluster number
          xor cx, cx
          mov cl, BYTE [bpbSectorsPerCluster] ; convert byte to word
          mul cx
          add ax, WORD [datasector] ; base data sector
          ret
;************************************************;
; Convert LBA to CHS
; AX=>LBA Address to convert
;
; absolute sector = (logical sector / sectors per track) + 1
; absolute head = (logical sector / sectors per track) MOD number of heads
; absolute track = logical sector / (sectors per track * number of heads)
;
;************************************************;
LBACHS:
          xor dx, dx ; prepare dx:ax for operation
          div WORD [bpbSectorsPerTrack] ; calculate
          inc dl ; adjust for sector 0
          mov BYTE [absoluteSector], dl
          xor dx, dx ; prepare dx:ax for operation
          div WORD [bpbHeadsPerCylinder] ; calculate
          mov BYTE [absoluteHead], dl
          mov BYTE [absoluteTrack], al
          ret
;************************************************;
; Reads a series of sectors
; CX=>Number of sectors to read
; AX=>Starting sector
; ES:BX=>Buffer to read to
;************************************************;
ReadSectors:
     .MAIN:
          mov di, 0x0005 ; five retries for error
     .SECTORLOOP:
          push ax
          push bx
          push cx
          call LBACHS ; convert starting sector to CHS
          mov ah, 0x02 ; BIOS read sector
          mov al, 0x01 ; read one sector
          mov ch, BYTE [absoluteTrack] ; track
          mov cl, BYTE [absoluteSector] ; sector
          mov dh, BYTE [absoluteHead] ; head
          mov dl, BYTE [bsDriveNumber] ; drive
          int 0x13 ; invoke BIOS
          jnc .SUCCESS ; test for read error
          xor ax, ax ; BIOS reset disk
          int 0x13 ; invoke BIOS
          dec di ; decrement error counter
          pop cx
          pop bx
          pop ax
          jnz .SECTORLOOP ; attempt to read again
          int 0x18
     .SUCCESS:
          mov si, msgProgress
          call Print
          pop cx
          pop bx
          pop ax
          add bx, WORD [bpbBytesPerSector] ; queue next buffer
          inc ax ; queue next sector
          loop .MAIN ; read next sector
          ret
;*********************************************
; Bootloader Entry Point
;*********************************************
main:
     ;----------------------------------------------------
     ; code located at 0000:7C00, adjust segment registers
     ;----------------------------------------------------
     
          cli ; disable interrupts
          mov ax, 0x07C0 ; setup registers to point to our segment
          mov ds, ax
          mov es, ax
          mov fs, ax
          mov gs, ax
     ;----------------------------------------------------
     ; create stack
     ;----------------------------------------------------
     
          mov ax, 0x0000 ; set the stack
          mov ss, ax
          mov sp, 0xFFFF
          sti ; restore interrupts
     ;----------------------------------------------------
     ; Display loading message
     ;----------------------------------------------------
     
          mov si, msgLoading
          call Print
          
     ;----------------------------------------------------
     ; Load root directory table
     ;----------------------------------------------------
     LOAD_ROOT:
     
     ; compute size of root directory and store in "cx"
     
          xor cx, cx
          xor dx, dx
          mov ax, 0x0020 ; 32 byte directory entry
          mul WORD [bpbRootEntries] ; total size of directory (ax = 0x0020 * 224)
          div WORD [bpbBytesPerSector] ; sectors used by directory (ax = 0x0020 * 224 / 512)
          xchg ax, cx ; swap(ax, cx) cx=14
          
     ; compute location of root directory and store in "ax"
     
          mov al, BYTE [bpbNumberOfFATs] ; number of FATs (2, ax = 2)
          mul WORD [bpbSectorsPerFAT] ; sectors used by FATs (9, ax = 18)
          add ax, WORD [bpbReservedSectors] ; adjust for bootsector(1, ax = 19)
          mov WORD [datasector], ax ; base of root directory([datasector] = 19)
          add WORD [datasector], cx ; [datasector] = 19 + 14 = 33
          
     ; read root directory into memory (7C00:0200)
     
          mov bx, 0x0200 ; copy root dir above bootcode
          call ReadSectors
     ;----------------------------------------------------
     ; Find stage 2
     ;----------------------------------------------------
     ; browse root directory for binary image
          mov cx, WORD [bpbRootEntries] ; load loop counter
          mov di, 0x0200 ; locate first root entry
     .LOOP:
          push cx
          mov cx, 0x000B ; eleven character name
          mov si, ImageName ; image name to find
          push di
     rep cmpsb ; test for entry match
          pop di
          je LOAD_FAT
          pop cx
          add di, 0x0020 ; queue next directory entry
          loop .LOOP
          jmp FAILURE
     ;----------------------------------------------------
     ; Load FAT
     ;----------------------------------------------------
     LOAD_FAT:
     
     ; save starting cluster of boot image
     
          mov dx, WORD [di + 0x001A]
          mov WORD [cluster], dx ; file first cluster
          
     ; compute size of FAT and store in "cx"
     
          xor ax, ax
          mov al, BYTE [bpbNumberOfFATs] ; number of FATs
          mul WORD [bpbSectorsPerFAT] ; sectors used by FATs
          mov cx, ax
mul WORD [bpbBytesPerSector] ; fatsize = sectors used by FATS * bpbBytesPerSector (512)
mov WORD [fatsize], ax
     ; compute location of FAT and store in "ax"
          mov ax, WORD [bpbReservedSectors] ; adjust for bootsector
          
     ; read FAT into memory (7C00:0200)
          mov bx, 0x0200 ; copy FAT above bootcode
          call ReadSectors
     ; read image file into memory (0050:0000)
     
          mov ax, 0x0050
          mov es, ax ; destination for image
          mov bx, 0x0000 ; destination for image
          push bx
     ;----------------------------------------------------
     ; Load Stage 2
     ;----------------------------------------------------
     LOAD_IMAGE:
     
          mov ax, WORD [cluster] ; cluster to read
          pop bx ; buffer to read into
          call ClusterLBA ; convert cluster to LBA
          xor cx, cx
          mov cl, BYTE [bpbSectorsPerCluster] ; sectors to read
          call ReadSectors
          push bx
          
     ; compute next cluster
     
          mov ax, WORD [cluster] ; identify current cluster
          mov cx, ax ; copy current cluster
          mov dx, ax ; copy current cluster
          shr dx, 0x0001 ; divide by two
          add cx, dx ; sum for (3/2)
          mov bx, 0x0200 ; location of FAT in memory
          add bx, cx ; index into FAT
          mov dx, WORD [bx] ; read two bytes from FAT
          test ax, 0x0001
          jnz .ODD_CLUSTER
          
     .EVEN_CLUSTER:
     
          and dx, 0000111111111111b ; take low twelve bits
         jmp .DONE
         
     .ODD_CLUSTER:
     
          shr dx, 0x0004 ; take high twelve bits
          
     .DONE:
     
          mov WORD [cluster], dx ; store new cluster
          cmp dx, 0x0FF0 ; test for end of file
          jb LOAD_IMAGE
          
     DONE:
mov ax, 0x1000
mov es, ax
mov cx, 2 ; read 32 sectors
mov ax, 19 ; starting sector
mov bx, 0 ; to 0x10000
          call ReadSectors
%if 0
; backup the FAT
; ES
mov cx, word [fatsize]
mov si, 0x0200
mov ax, 0x1000
mov es, ax
mov di, 0
.loopfatmove:
lodsb
stosb
loop .loopfatmove
mov di, 0
mov ax, word [fatsize]
stosw
%endif
          mov si, msgCRLF
          call Print
          push WORD 0x0050
          push WORD 0x0000
          retf
          
     FAILURE:
     
          mov si, msgFailure
          call Print
          mov ah, 0x00
          int 0x16 ; await keypress
          int 0x19 ; warm boot computer
     fatsize dw 0x0000
     datasector dw 0x0000
     cluster dw 0x0000
     ImageName db "MYOS BIN"
     msgLoading db 0x0D, 0x0A, "Loading Boot Image ", 0x00
     msgCRLF db 0x0D, 0x0A, 0x00
     msgProgress db ".", 0x00
     msgFailure db 0x0D, 0x0A, "MISSING OS. Hit Any Key to Reboot", 0x0D, 0x0A, 0x00
     
          TIMES 510-($-$$) DB 0
          DW 0xAA55

2012年3月25日 星期日

Simple OS for Hard Disk

Linux原本就可寫入MBR,只要:

$ sudo umount /dev/sdc
$ sudo dd if=FreeBSD-8.2-RELEASE-i386-memstick.img of=/dev/sdc bs=64k
Mac稍微麻煩一點,因為磁碟工具程式似乎不支援不認得的File System:
要知道mount到哪兒,可以在Terminal(終端機)看

$ sudo mount
若己經有檔案系統,可先別急著在Finder上按退出,因為會連device都退出 (這裏假設是 /dev/disk1)
$ sudo diskutil umount /dev/disk1
或是
$ sudo diskutil umount [你USB碟的Label名稱]
接下來
$ sudo dd if=FreeBSD-8.2-RELEASE-i386-memstick.img of=/dev/disk1 bs=64k

Windows可以利用 Image Writer for Windows

接下來看MBR
MBR 磁區大致上分為 3 個區域
----------------------------  <-- 位移值 00H (0 Bytes)
|                          |
|                          |
| Boot Partition Loader    |
| 這一小段程式用來將可啟動 |
| 的作業系統分割區戴入     |
|                          |
|                          |
|                     -----|  <-- 位移值 1BEh (446 Bytes)
|---------------------|    |
| Partition Table          |
| 硬碟分割表          -----|
|                     |55AA|
----------------------------  <-- 位移值 200H (512 Bytes)
1. 第一個區域是程式區,稱為 Boot Partition Loader, 也有人稱為 Pre-Loader 或 Pre-Boot。這一段小程式用來將可啟動的作業系統分割區戴入 (應該說戴入可啟動作業系統分割區的啟動磁區 Boot Sector),並將控制權交給啟動磁區。其範圍從 000h 到 1BDh,共 446 Bytes。

2. 第二個區域是資料區,即硬碟分割表所在區域。其範圍從 1BEh 到 1FDh,共 64 Bytes。
這 64 Bytes 又劃分成四個區域,代表 4 個硬碟分割表

位移值 01BE ~ 01CD <-- 第一分割表
位移值 01CE ~ 01DD <-- 第二分割表
位移值 01DE ~ 01ED <-- 第三分割表
位移值 01EE ~ 01FD <-- 第四分割表

硬碟分割表的格式:
每個分表佔 16 Bytes, 其意義如下:

----------------------------------------------------------------------------
|位移值|大小 | 說明                                                        |
+------+-------------------------------------------------------------------+
|  00  |Byte | BOOT ID - 若為可開機的分割區則為 80h ~ FFh, 否則為 00h。    |
|      |     | 80h = C, 81h = D, 82h = E ... 以此類推                      |
|      |     | 以 fdisk 來說,若第一顆硬碟的分割區設為 Active 則 ID = 80h。 |
|      |     | 4 個分割表中, 只能有一個被設為可開機, 否則將會發生錯誤。    |
+------+-----+-------------------------------------------------------------+
|  01h |Byte | 此分割開始之磁頭編號                                        |
+------+-----+-------------------------------------------------------------+
|  02h |Byte | 此分割開始之磁區編號 (6 bits)                               |
|      |     | 最高的 2 個 bits(bit6-7), 為磁柱編號的 bit8-9             |
+------+-----+-------------------------------------------------------------+
|  03h |Byte | 此分割開始之磁柱編號 (10 bits)                              |
|      |     | bit8-9 放在位移值 02h 的 bit 6-7                            |
+------+-----+-------------------------------------------------------------+
|  04h |Byte | 作業系統識別碼                                              |
|      |     |   00 None                                                   |
|      |     |   01 DOS FAT-12 bits                                        |
|      |     |   02 XENIX root                                             |
|      |     |   03 XENIX usr                                              |
|      |     |   04 DOS FAT-16 bits < 32M                                  |
|      |     |   05 Extended                                               |
|      |     |   06 DOS FAT-16 bits > 32M                                  |
|      |     |   07 HPFS/NTFS                                              |
|      |     |   08 AIX                                                    |
|      |     |   09 AIX bootable                                           |
|      |     |   0A OS/2 Boot Manager                                      |
|      |     |   0B DOS FAT-32 bits (Int 13h extensions)                    |
|      |     |   0C DOS FAT Cylinder > 1024 (Int 13h extensions)            |
|      |     |   0E DOS FAT System (Int 13h extensions)                     |
|      |     |   0F DOS BigExtended (Int 13h extensions)                    |
|      |     |   20 SPF Boot manager                                       |
|      |     |   40 Venix 80286                                            |
|      |     |   41 PPC PReP Boot                                          |
|      |     |   51 Novell                                                 |
|      |     |   52 Microport                                              |
|      |     |   63 GNU HURD                                               |
|      |     |   64 Novell Netware                                         |
|      |     |   65 Novell Netware                                         |
|      |     |   75 PC/IX                                                  |
|      |     |   80 Old MINIX                                              |
|      |     |   81 Linux/MINIX                                            |
|      |     |   82 Linux swap                                             |
|      |     |   83 Linux native                                           |
|      |     |   85 Linux extended                                         |
|      |     |   93 Amoeba                                                 |
|      |     |   94 Amoeba BBT                                             |
|      |     |   A5 FreeBSD                                                |
|      |     |   A6 Open BSD                                               |
|      |     |   A7 NETSTEP                                                |
|      |     |   A9 NetBSD                                                 |
|      |     |   B7 BSDI fs                                                |
|      |     |   B8 BSDI swap                                              |
|      |     |   C7 Syrinx                                                 |
|      |     |   DB CP/M                                                   |
|      |     |   E1 DOS access                                             |
|      |     |   E3 DOS R/O                                                |
|      |     |   EB BeOS fs                                                |
|      |     |   F2 DOS secondary                                          |
|      |     |   FF BBT                                                    |
+------+-----+-------------------------------------------------------------+
|  05h |Byte | 此分割結束之磁頭編號                                        |
+------+-----+-------------------------------------------------------------+
|  06h |Byte | 此分割結束之磁區編號 (6 bits)                               |
|      |     | 最高的 2 個 bits(bit6-7), 為磁柱編號的 bit8-9             |
+------+-----+-------------------------------------------------------------+
|  07h |Byte | 此分割結束之磁柱編號 (10 bits)                              |
|      |     | bit8-9 放在位移值 06h 的 bit 6-7                            |
+------+-----+-------------------------------------------------------------+
|  08h |DWord| 此分割區前之磁區總數                                        |
+------+-----+-------------------------------------------------------------+
|  12h |DWord| 此分割之磁區總數                                            |
+------+-----+-------------------------------------------------------------+

真實模式和保護模式

真實模式下,段位址會被放在四個段暫存器中,即:程式碼段CS,資料段DS,堆堆疊段SS和附加段ES暫存器。這樣在加載數據或者控制程序運行的時候,只需要一個偏移量參數,CPU 會自動用對應段的起始位址加上偏移量參數來得到需要的位址段位址(16-bit)左移4位得到段基址(20-bit), 再加上該單元(Label)的段偏移量(16-bit)來得到其物理位址(20-bit),如圖左所示















在保護模式下,邏輯位址不再由(段位址:偏移位址)組成了, 而是由(段選擇子:偏移位址)表示,這裡的偏移位址也變成了 32 位的,所以段空間也比真實模式下大得多,偏移位址的意思和真實模式下並沒有本質不同, 但段位址的計算就要復雜一些了,段基址(Segment Base Address)被存放在段描述符(Segment Descriptor)中GDT(Global Descriptor Table, 全局段選擇子表)是保存著所有段選擇子的信息, 段選擇子(Segment Selector)是一個指向某個段選擇子的索引。