【发布时间】:2010-12-12 18:48:04
【问题描述】:
我正在浏览一些 16 位实模式的示例汇编代码。
我遇到过以下问题:
mov bx, cs
mov ds, bx
mov si, OFFSET value1
pop es
mov di, OFFSET value2
这是在做什么?那里有“偏移”有什么作用?
【问题讨论】:
标签: assembly x86 masm x86-16 16-bit
我正在浏览一些 16 位实模式的示例汇编代码。
我遇到过以下问题:
mov bx, cs
mov ds, bx
mov si, OFFSET value1
pop es
mov di, OFFSET value2
这是在做什么?那里有“偏移”有什么作用?
【问题讨论】:
标签: assembly x86 masm x86-16 16-bit
正如其他一些答案所说,offset 关键字是指与定义它的段的偏移量。但是请注意,段可能会重叠,并且一个段中的偏移量在另一段中可能不同。例如,假设您在实模式下有以下段
data SEGMENT USE16 ;# at segment 0200h, linear address 2000h
org 0100h
foo db 0
org 01100h
bar db 0
data ENDS
汇编器发现foo 位于data SEGMENT 基的偏移量0100h,因此无论DS 的值如何,它都会将值offset foo 放在时间。
例如,如果我们将 DS 更改为 data 段的基数以外的其他内容,汇编器会假设:
mov ax, 200h ; in some assemblers you can use @data for the seg base
mov ds, ax
mov bx, offset foo ; bx = 0100h
mov byte ptr [bx], 10 ; foo = 10
mov ax, 300h
mov ds, ax
mov bx, offset foo ; bx = 0100h
mov byte ptr [bx], 10 ; bar = 10, not foo, because DS doesn't match what we told the assembler
在第二个例子中DS 是0300h,所以DS 指向的段的基是03000h。这意味着ds:[offset foo] 指向地址03000h + 0100h 与02000h + 01100h 相同,后者指向bar。
【讨论】:
2000h 来自哪里?你知道基于其他一些未显示的东西,它是 seg 基础吗?通常你会使用@data 而不是数字文字,对吧? (不过,这很适合作为示例。)
<<4 = 左移 1 个十六进制数字。
它只是表示该符号的地址。如果你熟悉的话,它有点像 C 中的 & 运算符。
【讨论】:
offset 表示si 寄存器将等于变量value1 的偏移量(而不是其实际值)。偏移量是存储变量的内存段开头的地址。偏移量通常与 ds 段相关(在您的情况下,ds 和 cs 寄存器指向同一段)。
【讨论】:
在 x86 16bit 模式下,地址空间不是平坦的;相反,地址由偏移量和“段”组成。 “段”指向一个 64K 的空间,偏移量在该空间内。
【讨论】:
来自MASM Programmer's Guide 6.1(微软宏汇编程序)
偏移量运算符
地址常量是一种特殊类型的立即操作数,由偏移量或段值组成。 OFFSET 运算符返回内存位置的偏移量,如下所示:
mov bx, OFFSET var ; Load offset address有关 MASM 5.1 行为和 MASM 6.1 行为与 OFFSET 相关的差异的信息,请参阅附录 A。
由于不同模块中的数据可能属于单个段,因此汇编器无法知道每个模块在段内的真实偏移量。因此,var 的偏移量虽然是立即值,但直到链接时间才确定。
如果您仔细阅读,最终值是在您“链接”您的目标代码以创建 DLL/EXE 后确定的。在链接之前,您所拥有的只是一个立即值,它表示距段基地址的偏移量。
【讨论】:
偏移量基本上是与线段点(也称为基准点)的距离。 例如段地址是 0000 并且偏移量或逻辑地址是 0100 那么物理地址可以通过将两对相加来计算。 物理地址 = 0000+0100=0100 表示我们需要的位置在0100的地址上。 同样,如果段地址为 1DDD 且偏移量为 0100,则: 物理地址为:1DDD+0100=1EDD
表示我们的目的地是 1EDD。
【讨论】: