我正在学习汇编,我正在尝试制作一个可以在汇编中创建字符串的方法。 我开始尝试将一个字符串复制到另一个字符串并将该副本存储在变量中,以备将来使用。
我正在使用emu8086,我收到以下错误:
跳过未知的操作码:64
不是8086指令 - 尚不支持。
org 100h
jmp start
msg: db "Hello, World!", 0
a: db 0
start:
mov si,msg
mov di, a
call _make_str
mov a, di
mov dx, a
mov ah, 09h
int 21h
mov ah, 0
int 16h
ret
_make_str:
pusha
_next:
mov al, [si]
mov [di], al
inc si
inc di
cmp al, 0
jne _next
popa
ret
这个错误意味着什么,我做错了什么?
答案 0 :(得分:1)
你有点天真的期望是什么字符串。
msg: db "Hello, World!", 0
这被组装成14个字节的机器代码(每个字符是ASCII编码中的一个字节(有不同的编码,具有不同的特征,但emu8086是基于ASCII的),还有一个用于终止零。
a: db 0
这是作为零值的单字节组装的。
然后您的代码启动,在_make_str
内,它会将14个字节从地址msg
复制到地址a
。但地址a+1
等于start
,因此13个字符会覆盖代码本身的机器代码,覆盖call _make_str
和mov a,di
。然后在ret
,代码返回mov a,di
应该是的地址,但是字符串中已经存在字节64
,因此报告了未知的操作码。
emu8086具有内置调试器,因此请使用单步执行指令和内存视图来了解字符串的编译方式以及代码的作用。
在汇编程序中没有变量,db/dw/dd/...
之前的那些名称是“符号”,它们就像书签到计算机内存中,包含该值的第一个字节的地址。
如果您需要20个字节的内存用于19个字符的最大长字符串,那么您需要分配/保留20个字节的内存,内存不会自动增长,或者重新寻址内容以便为意外数据腾出空间
如果我不知道字符串可能有多长,如何初始化变长的变量怎么办?
您不使用未知长度数据。要么你知道数据可能有多长,要么你必须把它放在一边(高级编程语言也有限制,如果你足够努力,你就会打破“无限制”的概念)。
根据最大值的类型,方法可能会有所不同。
例如,如果您正在读取用户的名称,您可以说最大值为80个字节,并在数据区域中保留80个字节,就是这样,名称较长的用户会使您的应用程序崩溃,或者您是否正确编码,他将只能输入79或80个字符(取决于你是否需要零终结符,在80字节数组内)。
如果你正在阅读像商品描述这样的小文字,你不确切地知道它的最大值,但是你确定它要么在数千之内,要么是可怕的错误,那么你可以在堆栈上动态保留空间,比如{ {1}}并将文本存储在堆栈区域中。
如果您正在读取长数据,例如2 + GB文件的二进制编辑器,则必须有一些数组描述您当前在内存中的文件块,并使用所有可用内存动态交换/输出操作系统提供缓存(“堆”类型的内存分配),但如果用完了堆,现代操作系统将通过使用存储在磁盘上的虚拟内存(交换)来增加它。但是通过更好的算法和应用程序设计来避免这种情况仍然会更好。
同样在emu8086中,16位x86实模式的所有其他限制都适用,即在您的类似COM的示例中,您的整个代码+数据+堆栈必须适合单个64kiB段(从0x100偏移开始,甚至不满64kiB),除非您的代码将检查DOS以获取更多可用的段,并使用更多它们(在普通DOS中作为第一个应用程序加载COM文件后,您通常在当前段之后有大约500-580kiB的内存空间)。
生活在16位的世界并询问“不知道大小”是一种额外的痛苦,在16位的世界中你必须知道未来的尺寸,并为它们做好计划,否则你会很快遇到问题。 / p> 编辑:实际上......你可能会遇到不同的bug,或者很难说出哪一个。
sub sp,<length_of_text>
这些集合 mov si,msg
mov di, a
和si
在地址di
和msg
的内存中注册了两个字节(16位)的值。它是MASM语法,其中内存访问不需要a
。
要获取第一个字节的地址,您需要[]
或mov si, OFFSET msg
...所以现在我甚至不确定哪个内存和您覆盖的位置,因为您使用字符数据作为内存指针,但显然你会覆盖一些至关重要的东西。
使用emu8086调试器来了解具体情况。
(在您修复代码以正确加载地址之后,您将按照我在回答中描述的那样覆盖代码覆盖)
答案 1 :(得分:0)
您需要让变量有足够的空间来存储源字符串中的所有字符,现在它只有一个字节。另请查看rep movsb指令。