我对角色如何在装配中工作感到困惑。由于所有内容都是以位为单位,这是否意味着所有字符在寄存器中基本上只是十六进制版本/ ascii值?
例如,如果我想在寄存器中输入“我喜欢馅饼”它会显示为“48h 4C484B45h 504945h”吗?如果我想获得所有“i”字母,我需要使用像
这样的命令; "command to get string input"
getI:
cmp BYTE PTR [edx],48h
je L1
L1:
add [edx],1
loop getI
我基本上试图找到一种方法来隔离输入字符串中的字符。
答案 0 :(得分:2)
你的方法接近于工作:
getI:
cmp BYTE PTR [edx],'i' ; your assembler will know what that is
jne L1 ; skip the code for 'i' handling, if it's NOT an 'i'
; here you do what
; ever you want to
; with your 'i's here
L1:
add edx,1 ; better: 'inc edx'
loop getI ; loop only works, if you have CX loaded with the length of your "string"
; either use it, or check for 0 chars INSIDE the loop
你的CPU不关心你的“字符串”,它只是内存中的一个字节数。
你的“我喜欢馅饼”是字节“69h,20h,6ch,69h,6bh,65h,20h,70h,69h,65h,0”的ascii表示
当你将其中一个加载到一个寄存器中时,它只是一个字节值...字符串或字符没什么特别的
答案 1 :(得分:1)
这是否意味着所有字符在寄存器
中基本上只是十六进制版本/ 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'
除非你知道汇编时的字符串长度,否则你不会知道需要多少寄存器来保存整个东西。通常情况下,如果您正在实施strlen()
,则一次将4个或8个字符加载到寄存器中并使用某些SWAR bithack执行check if any of the bytes are zero之类的操作。
如果您知道所有字符都是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
,字或add dword [edx], 1
。你可能意味着inc edx
如果您知道该字符存在,则无需检查长度(或C样式隐式长度字符串中的终止零字节)。
e.g。
unsafe_strchr:
; ... get the char you want in al, and the pointer in esi
.search:
cmp byte [esi], al
jne .search
; esi holds to the location