ASMx86:如何在字符串中挑出一个字母?

时间:2016-03-31 04:35:29

标签: assembly x86 irvine32

我对角色如何在装配中工作感到困惑。由于所有内容都是以位为单位,这是否意味着所有字符在寄存器中基本上只是十六进制版本/ ascii值?

例如,如果我想在寄存器中输入“我喜欢馅饼”它会显示为“48h 4C484B45h 504945h”吗?如果我想获得所有“i”字母,我需要使用像

这样的命令
;   "command to get string input"  
getI:
    cmp BYTE PTR [edx],48h 
    je L1
L1: 
    add [edx],1
    loop getI  

我基本上试图找到一种方法来隔离输入字符串中的字符。

2 个答案:

答案 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表示 当你将其中一个加载到一个寄存器中时,它只是一个字节值...字符串或字符没什么特别的

顺便说一句:并非所有的注册都是平等的,有一些是有特殊目的的。您已选择edx作为“字符串指针”... x86 CPU具有索引寄存器,其中包含使用它们的专用指令,这将更好地为您服务。但那是一个不同的故事; - )

答案 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