当cmov指针和寄存器时,操作码和操作数的组合无效

时间:2016-03-12 09:46:40

标签: assembly

我想用汇编语言编写一段代码,它会将字符串中的所有大写字符更改为小写。但是,我想避免尽可能多的条件跳转。我尝试了以下代码:

Invalid combination of opcodes and operands

但是NASM在两条CMOV线路上都给出了compile 'com.android.support:design:23.1.1' compile 'com.squareup.picasso:picasso:2.5.2' compile 'com.squareup.retrofit:retrofit:1.9.0' compile 'com.squareup.okhttp:okhttp:2.4.0' 错误......我不明白,这些线路有什么问题?

3 个答案:

答案 0 :(得分:3)

来自英特尔手册中的描述o CMOVcc — Conditional Move

  

这些指令可以将16位,32位或64位值从存储器移动到通用寄存器或从一个寄存器   通用注册到另一个。

所以你可以这样做cmovb eax, [edx]cmovb edx, eax,但不是cmovb [edx], eax

一般来说,我无法理解你的代码。似乎edx包含字符串的地址。但是你从那个地址(mov eax, [edx])读取一个DWORD,即从字符串中读取4个字符,然后尝试将这4个字符用作add [eax], byte 'a' - 'A'中的地址。

答案 1 :(得分:1)

除非您使用的是16位或更长的UniCode字符串,CMOV对于您的情况来说不是最理想的,因为目标必须是r16 / r32 / r64。因此,选择BYTE内存操作数作为目标是不可能的,并且会导致Invalid combination of opcodes and operands错误。唯一的可能性是选择16或32或64位寄存器作为目标,然后将另一个“MOV”操作的最低字节复制到存储器目的地。

0F 47 /r            CMOVA r16, r/m16    RM  Valid   Valid   Move if above (CF=0 and ZF=0).  
0F 47 /r            CMOVA r32, r/m32    RM  Valid   Valid   Move if above (CF=0 and ZF=0).  
REX.W + 0F 47 /r    CMOVA r64, r/m64    RM  Valid   N.E.    Move if above (CF=0 and ZF=0).  

但我建议你使用ASCII表中的小写和小写字母仅在第5位(= 0x20)不同的情况下将字符串转换为小写的简单方法。

global tolower_cmov

tolower_cmov:
    enter 0, 0
    mov edx, [ebp + 8]

.back:
    test byte ptr [edx], 0xff
    jz .end
    or byte ptr [edx], 0x20
    inc edx
    jmp .back

    inc edx
    jmp .back
.end:
    leave  
    ret

P.S。:此代码仅依赖于处理字符(a-z,A-Z)。否则,您必须在OR操作码之前进行范围检查。

答案 2 :(得分:0)

Michael的帮助下,我找到了一个适合我需求的解决方案:

    global tolower_cmov

tolower_cmov:
    enter 0, 0
    mov edx, [ebp + 8]
.back:
    test [edx], byte 0xff
    jz .end

    xor eax, eax
    xor ecx, ecx

    mov eax, [edx]
    mov ecx, [edx]
    add ecx, dword 'a' - 'A'
    cmp [edx], byte 'A'
    cmovb ecx, eax
    cmp [edx], byte 'Z'
    cmova ecx, eax
    mov [edx], ecx

    inc edx
    jmp .back
.end:
    leave
    ret