[英]How addressing works in assembly x86 Real Mode? Why does label return different values?
我有兩種用於引導加載程序的代碼變體(它應該在引導加載程序代碼的 512b 之后移動 1kb 堆棧)。 起始物理地址始終為 0x7c00(標簽“start”)。 BIOS 將引導加載程序代碼復制到 RAM 中。 當我使用“MOV SP,開始+1024+512”時:
但是如果我寫“jmp start”處理器將總是 go 到地址 0x7c00。 它會計算
為什么“開始”在MOV和LMP中返回不同的值? 還是一樣,但在MOV處理器中不添加段,而在JMP中添加? 在這種情況下,“開始”是否會根據 DS:SI 而不是 CS:IP 計算,這也是真的嗎? 另一個例子。 如果我最后添加代碼
mov SI, main
lodsb ;write data from main to AL
處理器將始終 go 到完整的物理地址段+偏移量,並在寄存器AL中獲取值“S”。 SI將僅等於偏移量? 處理器會在 lodsb 執行期間添加段嗎?
額外問題:
處理器如何執行“jmp main”? 該指令位於“mov ds, ax”之上。 因此 2 變體中的代碼有錯誤,但它可以工作。
BIOS加載bootloader時CS寄存器的默認值是多少? 顯然 CS:IP 應該是 0x7c00。
1 個變體
[bits 16]
[org 0x7c00]
start: ;offset= 0x7c00
jmp main
db "Some data" ;actually fake BIOS Parameter Block(BPB)
main:
mov ax, 0
mov ds, ax ; data segment =0.
mov ss, ax ; stack segment = 0
mov sp, start+1024+512 ;stack pointer = 0x7c00+1024+512
2 變體
[bits 16]
[org 0x0000]
start: ;offset= 0x0000
jmp main
db "Some data" ;actually fake BIOS Parameter Block(BPB)
main:
mov ax, 0x07c0
mov ds, ax ; data segment =0x07c0.
mov ss, ax ; stack segment =0x07c0.
mov sp, start+1024+512 ;stack pointer = 0+1024+512
... 總是 go 到地址 0x7c00。 它會計算...
在分段 memory 模型中,您不僅應該考慮有效(物理)地址,而且您始終必須將地址視為實模式或 16 位保護模式下的 (16+16) 位值或 (16 +32) 位值在 32 位保護模式下。
假設您的程序包含指令mov al, cs:[100h]
。
該指令將從地址CS:0x100
讀取一些字節,該地址實際上是(CS<<4)+0x100
。
如果執行跳轉到0x7C0:0
,該指令將訪問地址(0x7C0<<4)+0x100=0x7D00
; 如果執行跳轉到0:0x7C00
,該指令將訪問地址(0<<4)+0x100=0x100
處的 memory。
這意味着如果您跳轉到0x7C0:0
或0:0x7C00
,您的程序會做一些不同的事情。 為此,據說0x7C0:0
和0:0x7C00
是兩個不同的地址。
假設main
位於物理地址0x7C40
。
這意味着main
的地址既不是0x7C40
也不是0x40
,而是0:0x7C40
(在“變體 1”中)或者是0x7C0:0x40
(在“變體 2”中),因為您總是必須將地址指定為對段和偏移量。
在保護模式下的分段 memory 模型中,這更加復雜,使用正確的分段更為重要!
SI 將僅等於偏移量?
在這種情況下,“開始”是否會根據 DS:SI 而不是 CS:IP 計算,這也是真的嗎?
lodsb
指令訪問地址DS:SI
, stosb
訪問ES:DI
。
這意味着SI
只保存偏移量, DS
只保存段。
變體 1 和 2 會將不同的值加載到SI
寄存器,因為main
在一個變體中位於地址0:0x7C40
(這意味着: SI=0x7C40
),而在另一個變體中位於0x7C0:0x40
( SI=0x40
)。
因此,在變體 1 中,您必須設置DS=0
,在變體 2 中,您必須設置DS=0x7C0
。
在一種情況下, lodsb
將訪問地址0:0x7C40
,在另一種情況下, lodsb
將訪問地址0x7C0:0x40
。 在這兩種情況下,訪問 RAM 中的相同字節:物理地址0x7C40
。
處理器如何執行“jmp main”? 該指令位於“mov ds, ax”之上。 因此 2 變體中的代碼有錯誤,但它可以工作。
JMP
指令有兩種變體:
一種變體不會將固定值寫入IP
寄存器,但會向IP
寄存器添加一些常數值。 因此,如果將0x40
添加到0x7C0:0
,代碼執行將在0x7C0:0x40
繼續。 如果將0x40
添加到0:0x7C00
,代碼執行將在0:0x7C40
繼續。 在這兩種情況下,下一條指令都位於物理地址0x7C40
。 (可能jmp main
就是這個變種。)
另一種變體采用一對段和偏移量作為參數。 您不能跳轉到地址0x7C40
,但您可以跳轉到地址0:0x7C40
或地址0x7C0:0x40
。
BIOS加載bootloader時CS寄存器的默認值是多少?
有一些 BIOS 會跳轉到0x7C0:0
,但標准似乎是0:0x7C00
。
出於這個原因,許多引導加載程序執行跳轉到0x7C0:0x60
(例如)以確保CS
寄存器具有定義的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.