You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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"

原理说明

  1. 汇编阶段的常量计算
    NASM会在汇编过程中直接计算a+b这个表达式的值,这里的a和b是数据段中变量的偏移地址(32位PE程序中,数据段的基地址由操作系统加载时确定,但偏移地址在汇编时就已固定)。
  • 因为a是数据段的第一个变量,它的偏移地址为0x00;b是db类型(占1字节),紧跟在a之后,所以b的偏移地址是0x01。
  • 两者相加的结果是0x00 + 0x01 = 0x01,这个值会被作为8位立即数编译到mov ah, imm8指令中,所以调试时看到AH = 01h。
  1. 语法合法性的原因
    NASM允许在立即数操作数位置使用汇编时可确定结果的表达式,只要最终结果符合目标寄存器的宽度要求——这里ah是8位寄存器,0x01是8位值,完全符合要求,因此语法合法。注意这不是运行时的地址运算,而是汇编阶段就完成的常量计算。

  2. 正确实现变量值相加的写法
    如果你的真实需求是把变量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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 15:47:02