32位NASM汇编中指针加法为何可行?求原理解析
NASM中
mov ah, a+b的工作原理解析 问题描述
我在NASM中编写了如下代码:
mov ah, a+b
其中变量a和b在数据段定义为:
a db 0 b db 32
我清楚NASM里[a]、[b]才表示取变量的值,a、b本身是变量的偏移地址,但这段代码却能正常运行,调试器显示AH = 01h,我完全无法理解两个地址相加后赋值给ah的可行性与工作原理。
完整测试代码
bits 32 ; assembling for the 32 bits architecture ; declare the EntryPoint (a label defining the very first instruction of the program) global start ; declare external functions needed by our program extern exit ; tell nasm that exit exists even if we won't be defining it import exit msvcrt.dll ; exit is a function that ends the calling process. It is defined in msvcrt.dll ; msvcrt.dll contains exit, printf and all the other important C-runtime specific functions ; our data is declared here (the variables needed by our program) segment data use32 class=data a db 0 b db 32 ; our code starts here segment code use32 class=code start: mov ah, a+b ; exit(0) push dword 0 ; push the parameter for exit onto the stack call [exit] ; call exit to terminate the program
汇编环境配置(Notepad++插件)
; use the following placeholders: ; %n - notepad++ dir ; %s - source name (without path or extension) ; %d - source dir [Build] ; the path for the build result target="%d\%s.exe" ; the build command line command="cmd /Q /c ""%n\..\nasm\nasm.exe" -fobj "%d\%s.asm" -l "%d\%s.lst" -I"%n\..\nasm\\" && "%n\..\nasm\ALINK.EXE" -oPE -subsys console -entry start "%d\%s.obj""" ; the files to remove after the build filesToRemove="%d\%s.obj" [Run] ; the command to run command="cmd /Q /c ""%d\%s.exe" & echo. & pause"" ; if a target is specified, it will be checked to have a later date than the source target="%d\%s.exe" [Debug] ; the command for debug command="cmd /Q /c ""%n\..\ollydbg\ollydbg.exe" "%d\%s.exe""" ; if a target is specified, it will be checked to have a later date than the source target="%d\%s.exe" [Build custom] ; the path for the build result target="%d\%s.exe" ; the build command line command="cmd /Q /c ""%n\..\nasm\nasm.exe" -fobj "%d\%s.asm" -l "%d\%s.lst" -I"%n\..\nasm\\" && "%n\..\nasm\ALINK.EXE" -oPE -subsys console -entry start "%d\%s.obj""" ; the files to remove after the build filesToRemove="%d\%s.obj" [Run custom] ; the command to run command="cmd /Q /c ""%d\%s.exe" & echo. & pause"" ; if a target is specified, it will be checked to have a later date than the source target="%d\%s.exe"
原理说明
- 汇编阶段的常量计算
NASM会在汇编过程中直接计算a+b这个表达式的值,这里的a和b是数据段中变量的偏移地址(32位PE程序中,数据段的基地址由操作系统加载时确定,但偏移地址在汇编时就已固定)。
- 因为
a是数据段的第一个变量,它的偏移地址为0x00;b是db类型(占1字节),紧跟在a之后,所以b的偏移地址是0x01。 - 两者相加的结果是
0x00 + 0x01 = 0x01,这个值会被作为8位立即数编译到mov ah, imm8指令中,所以调试时看到AH = 01h。
语法合法性的原因
NASM允许在立即数操作数位置使用汇编时可确定结果的表达式,只要最终结果符合目标寄存器的宽度要求——这里ah是8位寄存器,0x01是8位值,完全符合要求,因此语法合法。注意这不是运行时的地址运算,而是汇编阶段就完成的常量计算。正确实现变量值相加的写法
如果你的真实需求是把变量a和b存储的值相加后存入ah,正确的代码应该是:
mov al, [a] ; 取出a的值到al add al, [b] ; al加上b的值 mov ah, al ; 将结果存入ah
或者更简洁的写法:
movzx ax, byte [a] ; 零扩展a的值到ax add al, [b] ; al加上b的值,结果在ax中,ah为高8位(这里a是0,b是32,结果ah=0,al=32)
内容的提问来源于stack exchange,提问作者Darius
相关产品推荐
相关产品推荐

