此代码的目标是扫描数据库,每次出现“no”字样时,它将替换为“**”,程序将停在char'$'
IDEAL
MODEL small
STACK 100h
DATASEG
; --------------------------
; Your variables here
; --------------------------
String db ' no, I am not no ? yes no reality $'
CODESEG
start:
mov ax, @data
mov ds, ax
; --------------------------
; Your code here
; --------------------------
mov bx, 0
cmp [byte ptr bx], '$'
jz exit
cmp [word ptr bx], 'no'
jz switch
first:
inc bx
cmp [byte ptr bx], '$'
jz exit
cmp [word ptr bx], 'no'
jnz first
switch:
mov [word ptr bx], '**'
jmp first
exit:
mov ax, 4c00h
int 21h
END start
答案 0 :(得分:1)
什么样的"数据库" ? db
代表"定义字节",而不是数据库。
同样,当你将它与字符串文字结合使用时,实际上是在定义几个字节,而不只是一个字节。
jz exit
...比较之后,通常使用别名je
作为"跳跃等于" 缩短 - 它&#39 ; s是相同的jz
指令,但对于检查代码的任何人来说,与非零值进行比较会更好地读取。
mov bx,0
这是获取数据偏移的脆弱方式,而是使用定义的标签:mov bx, OFFSET String
或lea bx,[String]
。
如果您要加载带有String-1
偏移量的bx(第一个inc bx
将其固定为+0地址),您也可以完全重用循环代码。因此,您可以在开头避免使用两个重复的cmp
说明。
最后......检查列表文件或反汇编,比较cmp [word ptr bx], 'no'
的值是什么。由于你没有提到你的汇编程序,所以不可能告诉你,你的汇编是如何编译的。
例如,NASM对字符串文字有例外,它将把它组合为两个字节' n'' o'在人类预期的字符串顺序" (字值0x6F6E
),即使它被标记为word
大小值(但您没有使用NASM,因为[word ptr bx]
将是无效的语法)。
在MASM / TASM中我猜想汇编程序会将word
值视为真正的16位值,即'n'*256+'o' = 0x6E*256 + 0x6F = 0x6E6F
,即它会检测" on"内存中的子字符串,因为x86是little-endian,所以word 0x6E6F
被分解为单个字节6F 6E = 'o', 'n'
。
而是使用cmp [word ptr bx],('n' + 'o'*256)
来确保字母的顺序是正确的(通过小端方式)。
/l
命令行开关生成列表文件):
16 0000 81 3F 6E6F cmp [word ptr bx],'no'
17 0004 81 3F 6F6E cmp [word ptr bx],'n'+256*'o'
从指令操作码(81 3F 6E6F
vs 81 3F 6F6E
)可以看出,您的'no'
正在"上搜索子字符串"
有趣的是,你必须完全理解little-endian和byte vs word细微之处,因为如果你将机器码检查为ASCII文本,那么第一个变体包含" no" string(将搜索" on"),第二个包含" on" string(将搜索" no")。
实际上我混淆了自己,在操作码中,单词值显示为单词值,即81 3F 6E6F
以字节81 3F 6F 6E
表示,当以ASCII格式查看时,它将包含错误的" on& #34;,它是它寻找的子字符串。
为什么* 256有效...
byte
是8位。word
是16位。这意味着,当您指示CPU写入word
值(如1500)时,它将首先存储最低有效字节,然后存储其后的最高有效字节。如果是1500 =那两个字节,220和5.因为5 * 256 + 220 = 1500.在十六进制格式化中(这使得经验丰富的asm程序员更喜欢它)它更容易看到:1500 = 05DCh
,存储的字节首先是0DCh
,然后是05h
。
现在所谓的初学者"字符串"在TASM中是ASCII编码的,单个字母=单个字节(现代UTF-8编码确实使用每个字母的可变字节长度,尽管值低于128的代码与ASCII兼容,因此任何7位ASCII文本也是有效的UTF-8文本)。
因此像' no, I am not no ? yes no reality $'
这样的文本被组合成字节:
20 6E 6F 2C 20 49 20 61 6D 20 6E 6F 74 20 6E 6F 20 3F
20 79 65 73 20 6E 6F 20 72 65 61 6C 69 74 79 20 24
注意" no"由两个字节6E 6F
组成。
如果您将其视为字值,例如mov ax,[String+1]
,则CPU将使用字节值的小端编码,ax
将等于06F6Eh
(第一个字节)低8位,第二个字节高8位)。
现在通过编写'n' + 'o'*256
,您手动决定将哪个字母作为第一个字节进行检查('n'
..这是从完整数学'n' * 256^0
缩短的(通过^我的意思是这里的功率,不是xor)),它将被检查为第二个字节('o'*256
,其中256是256的第一个幂)。
当256的幂出现时...每个字节是8位,因此它可以存储0到255的值(当被解释为无符号整数时),即恰好256 = 2 8 不同的值。因此,当您在单字节上用完值时,并且在第二个较高字节上执行+1时,您在256个边界处执行此操作...而第三个和第四个字节(对于32b值)则为256 2 值和256 3 值。
即。 32位值16,909,060将作为四个字节04 03 02 01
存储在内存中。验证:4 * 256 0 + 3 * 256 1 + 2 * 256 2 + 1 * 256 3 = 16,909,060 .... yaaay ..
因此,如果你想同时检查两个字母,作为一个字值,你必须寻找字值06F6Eh
(测试6Eh = 'n'
的第一个字节和第二个字节{{1 }})。