Pointers 汇编行为(nasm)中的指针算法

Pointers 汇编行为(nasm)中的指针算法,pointers,assembly,nasm,Pointers,Assembly,Nasm,我的数据段如下所示: segment data use32 class=data v db 4 v1 db 4 v2 db 4 v3 db 7 为什么mov-bh,v是语法错误,但mov-bh,v+v1或mov-bh,v+v1+v2不是?事实上,v+v1加上2个指针不是有效的指针算法。此外,调试器告诉我们,bh被移动了一个小数字,比如6,但是考虑到地址是非常大的数字,nasm似乎在幕后做了一些减法 我使用nasm 1.6 NASM能够在这些有效地址上做代数运算

我的数据段如下所示:

segment data use32 class=data
    v db 4
    v1 db 4
    v2 db 4 
    v3 db 7
为什么
mov-bh,v
是语法错误,但
mov-bh,v+v1
mov-bh,v+v1+v2
不是?事实上,v+v1加上2个指针不是有效的指针算法。此外,调试器告诉我们,bh被移动了一个小数字,比如6,但是考虑到地址是非常大的数字,nasm似乎在幕后做了一些减法

我使用nasm 1.6

NASM能够在这些有效地址上做代数运算,所以看起来不一定合法的事情是完全正确的

我喜欢NASM将所有标签都视为地址的方式,但它的地址代数肯定缺乏一致性,并且可能导致混淆

以你为例,

segment data use32 class=data
v       db      4    ; relative address = 0
v1      db      4    ; relative address = 1
v2      db      4    ; relative address = 2
v3      db      7    ; relative address = 3
下面的操作

        mov     bx, v
将重新定位的地址(不是0)移动到
bx

        mov     bh, v
将导致错误:
OBJ格式只能处理16或32字节的重定位
,因为
bh
是8位的,重定位将不起作用

        mov     bh, [v]
这是将
v
中的值加载到
bh
的正确方法

Nasm还允许在地址上使用代数,如

        mov     bh, [v + v1 - v2]     ; 1 + 1 - 1 = 1
        mov     bh, [v * 2 - v1]      ; 2 - 1 = 1
        mov     bh, [v * 3 - v1 * 2]  ; 3 - 2 = 1
标签总数必须为1(或0,见下文)。所以它不允许这样的代码

        mov     bh, [v + v1]          ; 1 + 1 = 2
        mov     bh, [v - v1 * 2]      ; 1 - 2 = -1
        mov     bh, [v * 3 - v1]      ; 3 - 1 = 2
由于
无效的有效地址:无法使用段基乘数
相对调用OBJ格式不支持的绝对地址

奇怪的是,它允许这些

        mov     bh, [v - v1]          ; 1 - 1 = 0
        mov     bh, [v * 3 - v1 * 3]  ; 3 - 3 = 0
生成的代码使用绝对地址。我希望NASM会发出警告,但事实并非如此。对我来说,这是一个错误

最后,NASM还允许在没有
[]
的地址上使用代数,没有任何限制

        mov     bh, v - v1            ; same as mov bh, 0-1
        mov     bh, v + v1            ; same as mov bh, 0+1
        mov     bh, v + v1 * 2 + v3   ; same as mov bh, 0+1*2+3
第一条当然有道理。其他选项与其他选项结合使用时会很有用:

        mov     eax, v2 + v3
        sub     eax, v + v1

总之,当单独使用
v
时(
mov-ebx,v
),NASM使用重新定位的地址。当执行地址代数时(
movebx,v+v1-v2
),NASM使用相对地址。因此,是的,这有点令人困惑。

我不知道这是否有任何影响,但请尝试删除v1和v2行末尾的逗号。我对nasm不太了解,但您需要将内存模型声明为“扁平”吗?在nasm
mov bh中,v
试图将
v
符号(内存地址)放入
bh
寄存器,32b模式下的内存地址为32b“宽”,因此该值将不适合
bh
(8位寄存器)。在MASM/TASM中,该行将编译为
mov-bh,BYTE PTR[v]
,从内存加载值,但在NASM中,如果需要值,则方括号是必需的,即
mov-bh,[v]
(要明确告诉汇编程序内存参数大小,NASM中的语法是
movzx-ebx,BYTE[v]
转换字节->dword…其他变量,如
mov bh,v+v1
将一起添加内存地址,并将结果截断为8位值。哦,您实际上知道您正在将内存地址加载到
bh
,而不是内存中的值…因此您忽略了x86寄存器的要点,它们的大小/别名。请检查请阅读本教程的基础知识:(这是MASM语法,但NASM非常类似)
bh
只有8位寄存器,因此当位模式被解释为无符号整数时,只有值0..255可用。我用NASM 2.13.02试用了您的源代码,并且
mov bh,v
的汇编效果很好(我的意思是,它显示了关于截断值的警告,但确实会产生预期的机器代码,将
v
地址的底部8位加载到
bh
)中。此外,它不喜欢
数据
段定义…您实际使用的是NASM吗?看起来更像是TASM/MASM语法。指出了mov bh,v的语法错误“OBJ格式只能处理16字节或32字节的重定位”,但例如,mov bh、v+v1将11字节移到bh中