【问题标题】:How to change the value of a variable in assembly如何在汇编中更改变量的值
【发布时间】:2026-02-10 05:05:01
【问题描述】:

我正在为我的 MikeOS 端口编写一些代码。它是用 NASM x86 16 位汇编编写的。我正在尝试更改我制作的变量以具有不同的值。它编译时没有错误,但是当我调用 os_print_string 时,它会打印一些奇怪的 ASCII 字符。代码如下:

    BITS 16
    ORG 32768
    %INCLUDE "mikedev.inc"



start:
    mov si, test2          ; give si test 2 value
    mov [test1], si        ; give test 1 si's value
    mov si, test1          ;now give test1's value to si
    call os_print_string   ; and print

test2 db "adsfasdfasdf", 0
test1 db "asdf", 0

我知道这段代码是多余的。我只需要一个关于如何更改变量值的解释。提前谢谢!

-瑞恩

【问题讨论】:

  • 您所做的是获取test2 的地址并将其存储在test1 的前两个字节中(即第一个"ad" 曾经所在的位置)。您不能在运行时更改test1 的地址。您可以做的是将内容(即所有字符)从test2 复制到test1。请记住,test1 没有足够的空间来容纳来自test2 的所有字符。
  • 回复迈克尔:感谢您的评论,但我想我可能不够清楚。我为 MikeOS 制作的这个项目是一种脚本语言。我试图弄清楚如何将一个变量的值分配给另一个变量(即字符串 a = b;)。
  • 在这种情况下,您可能不会按照当前代码中的方式实现字符串。 test1test2 更类似于 C 中的 char * const,即不能更改为指向其他任何地方的指针。

标签: variables assembly operating-system nasm interrupt


【解决方案1】:

又一个老问题,这是你等了 6.83 年的答案 :)

BITS 16
ORG 32768
%INCLUDE "mikedev.inc"

start:
mov si, test2
mov di, test1

.loop:
lodsb
or al, al
je .done
stosb
jmp .loop

.done:
mov si, test1
call os_print_string

test2 db "adsfasdfasdf", 0
test1 db "asdf        ", 0

确保 char 数组的长度相同,否则会中断 ^^ 但我相信你现在知道了^^

【讨论】:

  • or al, al 是一个古老的低效习语。 test al,althe normal good way 从寄存器设置 FLAGS。
  • 您的循环不会复制终止的 0 字节,因此如果源与目标缓冲区中先前的字符串长度不同,它将无法正常工作。您可以只使用 lodsb/stosb / test al,al / jnz .loop 停止使用标准循环结构复制 0。
  • 我显然不是最新的,我读到的每一篇旧文章都说使用 or reg, reg 而不是 test 或 cmp 是一种易于进行的微优化。另外,我不关心零,因为如果我不插入空格,test2 会比 test1 长,无论如何都会有效地搞砸存储在 test1 后面的一些其他数据。
  • 如果 test2 较短,那么你需要复制一个终结符。另外,我没有说比缓冲区长,我说的比它当前持有的字符串长。例如如果在其他一些东西之后 test1 持有db "xyz", 0, "xyzxyzxyz", 0,并且您复制了一个在 xyz 的第二个块中间结束的字符串,那么将 test1 作为 C 字符串读取将包括到第二个零字节末尾的尾随垃圾.
  • 另外,由于避免复制终止符会降低循环效率(test/jcc jmp,因为您没有剥离第一个部分迭代并“旋转”循环将条件放在底部),即使不需要,复制最后一个字节基本上也是一种胜利。