这是否意味着所有字符在寄存器中时基本上只是十六进制版本/ascii 值
是的,就像在 C 中一样,字符串只是 char 元素的数组。 char 只是一个窄整数类型,如 uint8_t。 (C 标准没有定义 char 是否有符号,所以如果您实际使用 C 并且想要无符号变量,请使用 uint8_t。)
无论如何,是的,在 asm 中,您应该将 ASCII 字符串中的字符视为 8 位整数,其中the value is their ASCII encoding。例如如果ax 的值来自[0..9],您可以使用以下命令将其转换为十进制数字:
add al, '0' ; '0' is a nice way to write 0x30
将较大的整数转换为多位数的十进制字符串显然更复杂,需要除以或乘以 10。
如果寄存器中有字母 ASCII 字符,可以将其强制为小写、大写或翻转
or al, 0x20 ; tolower
and al, ~0x20 ; toupper
xor al, 0x20 ; opposite
'a' - 'A' 是 0x20,范围不跨越编码空间内的 0x20 边界。 (即所有小写字母都设置了该位,而大写字母都没有)。要检查 ascii 字符是否为字母,请参阅 my answer on a question about case-flipping for letters only
如果我把“我喜欢馅饼”放在寄存器里……
在一个寄存器中一次处理多个字符很棘手,但对于高性能来说是必不可少的。编写只保留指向字符串中某个位置的指针并一次处理一个字节的代码会更容易。
NASM 和 MASM 有 syntax for multi-character constants,所以你可以做类似的事情
mov eax, 'abcd' ; put those bytes into eax, like if you'd loaded from db 'a', 'b', 'c', 'd'
除非您在汇编时知道字符串长度,否则您将不知道保存整个字符串需要多少个寄存器。通常,您一次将 4 或 8 个字符加载到寄存器中,并使用一些 SWAR bithack 来执行 check if any of the bytes are zero 之类的操作,例如,如果您正在实现 strlen()。
如果你知道所有的字符都是 ASCII 字母,你可以强制它们全部小写
mov eax, [rsi]
or eax, 0x20202020 ; packed tolower on all 4 chars
你的循环
您正在尝试实现strchr(const char *s, int c)?
getI:
cmp BYTE PTR [edx],48h ; so far so good
je L1 ; goes to L1 whether the branch is taken or not
L1:
add [edx],1 ; increments the data pointed to by edx, not edx itself.
loop getI ; If ECX is the string length, this is ok. also loop is slow, don't use
另外,add [edx],1 不会汇编,因为操作数大小不明确。可以是add byte [edx], 1、word 或add dword [edx], 1。你的意思可能是inc edx
如果您知道该字符存在,则无需检查长度(或 C 样式隐式长度字符串中的终止零字节)。
例如
unsafe_strchr:
; ... get the char you want in al, and the pointer in esi
.search:
inc esi
cmp byte [esi-1], al
jne .search
; esi holds to the location