簡體   English   中英

匯編 x86 實模式中的尋址如何工作? 為什么 label 返回不同的值?

[英]How addressing works in assembly x86 Real Mode? Why does label return different values?

我有兩種用於引導加載程序的代碼變體(它應該在引導加載程序代碼的 512b 之后移動 1kb 堆棧)。 起始物理地址始終為 0x7c00(標簽“start”)。 BIOS 將引導加載程序代碼復制到 RAM 中。 當我使用“MOV SP,開始+1024+512”時:

  1. SP將是 0x7c00 + 1024 + 512,因為物理地址應該是SS:SP = 0<<4 + 0x7c00 + 1024 + 512。所以“開始” = 0x7c00
  2. SP將是 0 + 1024 + 512,因為物理地址應該是SS:SP = 0x07c0<<4 + 1024 + 512。所以“開始” = 0x0000

但是如果我寫“jmp start”處理器將總是 go 到地址 0x7c00。 它會計算

  1. 0 + 0x07c0
  2. 0x07c0<<4 + 0

為什么“開始”在MOVLMP中返回不同的值? 還是一樣,但在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:00:0x7C00 ,您的程序會做一些不同的事情。 為此,據說0x7C0:00:0x7C00是兩個不同的地址。

假設main位於物理地址0x7C40

這意味着main的地址既不是0x7C40也不是0x40 ,而是0:0x7C40 (在“變體 1”中)或者是0x7C0:0x40 (在“變體 2”中),因為您總是必須將地址指定為對段和偏移量。

在保護模式下的分段 memory 模型中,這更加復雜,使用正確的分段更為重要!

SI 將僅等於偏移量?
在這種情況下,“開始”是否會根據 DS:SI 而不是 CS:IP 計算,這也是真的嗎?

lodsb指令訪問地址DS:SIstosb訪問ES:DI

這意味着SI只保存偏移量, DS只保存段。

變體 1 和 2 會將不同的值加載到SI寄存器,因為main在一個變體中位於地址0:0x7C40 (這意味着: SI=0x7C40 ),而在另一個變體中位於0x7C0:0x40SI=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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM