Base64 汇编程序填充数组错误“操作数不同大小”Visual Studio

Posted

技术标签:

【中文标题】Base64 汇编程序填充数组错误“操作数不同大小”Visual Studio【英文标题】:Base64 Assembler Fill Array Error "Operands different sizes" Visual Studio 【发布时间】:2015-11-02 22:02:48 【问题描述】:

我试图在 Visual Studio 的内联汇编器中制作 Base64Encode。

我有这个功能

char* Base64Encode(char* data, int len)

// Tabelle mit den Zeichen für die Codierung
const char* encodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//
char* result;   


if (len > 0)            // sonst gibt es nichts zu tun ...

    int encodedLength   = ((len + 2) / 3) * 4;      // effektiv die Ganzzahlfassung von ceil(length/3)*4
    result = new char[encodedLength+1];             // +1 wg. Null-Terminierung
    _asm
               
        mov esi,data
        mov edi,encodeTable

        xor eax, eax
        // get 3 bytes
        mov ah, byte ptr[esi]
        mov al, byte ptr[esi+1]
        shl eax,16
        mov ah, byte ptr[esi+2]

        //
        mov edx,eax
        shl eax,6

        shr edx, 26
        mov bl, byte ptr[edi + edx]    
        mov [result],bl

        //
        mov edx, eax
        shl eax, 6                                    

        shr edx, 26
        mov bl, byte ptr[edi + edx]            
        mov[result+1], bl

        //manipulate in edx bitset3
        mov edx, eax
        shl eax, 6

        shr edx, 26
        mov bl, byte ptr[edi + edx]
        mov[result+2], bl

        //manipulate in edx bitset4
        mov edx, eax
        shl eax, 6

        shr edx, 26
        mov bl, byte ptr[edi + edx]
        mov[result+3], bl


    

else

    result = "";

return result;

编码工作正常,我在 bl 中总是有正确的字母,但输出不起作用(结果数组没有用字母填充,我收到操作数大小不同的错误,我只被允许在 __asm 函数中进行更改)。

有人可以帮助我如何用我在 bl 中得到的字母填充结果数组吗?如果我注释掉所有结果行,调试总是会在 bl 中显示正确的字母。

编辑:

当我使用字节指针时,结果数组中什么也没有。

有什么想法吗?

EDIT2:

【问题讨论】:

单步执行汇编代码有什么建议? ***.com/questions/14905769/… 不确定这是否是你的意思,在edit2中你看到bl中有一个A,下一步它应该在结果数组中,但结果数组只是0'/0 ' 考虑一下。 mov [result],bl(最好写成mov byte ptr [result],blbl 的内容移动到resultresult 实际上是一个指向字符串的指针(由new 返回)。你缺少一个级别间接。您实际上更改了 pointer 本身,而不是 result 中包含的指针处的数据。 那么您需要在开始时获取变量 resultcontents(这将是 new 返回的指针)你的 asm 块。将该地址移动到带有类似 mov ecx, dword ptr [result] 的寄存器(例如ecx)中。 ECX 现在应该是您实际缓冲区的指针。现在,无论您在 asm 块中使用 result 的任何位置,都将其更改为 ecx。所以mov [result],bl 会变成mov byte ptr [ecx],blmov[result+1], bl 会变成mov byte ptr [ecx+1], bl 等等。 这完全是一个不同的问题。您可以选择像EDX 这样的未使用寄存器作为循环变量。例如,您可以执行mov byte ptr [ecx + edx], blmov byte ptr [ecx + edx + 3], bl 之类的操作。最后一个是基于索引加位移寻址。 【参考方案1】:

您的代码中的问题是间接问题。您可以在 C++ 代码中像这样定义和初始化变量 result

char* result; 
result = new char[encodedLength+1]; 

result 是一个内存位置,它保存指向new 返回的字符数组的指针。 result 不是存储数据的内存位置,而是包含指向该数据区域的指针。然后,您可以像这样在 ASM 块中访问它:

mov [result],bl

编译器/汇编器(MASM) 在说操作数不同大小 时警告说存在操作数不匹配。它知道result 是一个32 位指针(不是单个字符)的位置。由于result 是包含指针的地址,因此上面的代码会将bl 的内容移动到内存位置result。这会改变指针(由new 返回)而不是result 指向的内容。

你需要在这里处理间接性。您想要获取存储在result 中的地址并将其用作内存寻址的 base。您可以选择一个可用的寄存器,如 ECXMOVresult 的内容放入其中。您可以在 ASM 块的顶部使用类似的东西来做到这一点:

mov ecx, dword ptr [result]

这会在内存位置result 中获取 32 位(dword)值并将其存储在 ECX 中。现在我们有了字符缓冲区开头的内存位置,我们现在可以修改 ASM 块中result 的所有引用并将其更改为 ECX。例子:

mov [result],bl 

会变成:

mov byte ptr [ecx],bl 

mov[result+1], bl 

会变成:

mov byte ptr [ecx+1], bl

第二个例子叫做base plus displacement (or offset) addressing。该链接还描述了 x86 上的所有寻址模式。如果您使用的是 16 位代码(您不是),则可用于基址和索引的寄存器选择有一些额外的限制。

user3144770 还指出你没有终止你的字符串(你只为它分配了空间),所以在你的 ASM 底部阻止你应该可能使用类似的东西:

mov byte ptr[ecx+4], 0

通过上面的更改,您的代码可能如下所示:

char* Base64Encode(char* data, int len)

    // Tabelle mit den Zeichen für die Codierung
    const char* encodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    //
    char* result;

    if (len > 0)            // sonst gibt es nichts zu tun ...
    
        int encodedLength = ((len + 2) / 3) * 4;      // effektiv die Ganzzahlfassung von ceil(length/3)*4
        result = new char[encodedLength + 1];         // +1 wg. Null-Terminierung
        _asm
        
            mov esi, data
            mov edi, encodeTable

                mov ecx, dword ptr [result]
                xor eax, eax
                // get 3 bytes
                mov ah, byte ptr[esi]
                mov al, byte ptr[esi + 1]
                shl eax, 16
                mov ah, byte ptr[esi + 2]

                //
                mov edx, eax
                shl eax, 6

                shr edx, 26
                mov bl, byte ptr[edi + edx]
                mov byte ptr [ecx], bl

                //
                mov edx, eax
                shl eax, 6

                shr edx, 26
                mov bl, byte ptr[edi + edx]
                mov byte ptr [ecx + edx + 1], bl

                //manipulate in edx bitset3
                mov edx, eax
                shl eax, 6

                shr edx, 26
                mov bl, byte ptr[edi + edx]
                mov byte ptr [ecx + 2], bl

                //manipulate in edx bitset4
                mov edx, eax
                shl eax, 6

                shr edx, 26
                mov bl, byte ptr[edi + edx]
                mov byte ptr [ecx + 3], bl

                mov byte ptr[ecx + 4], 0
        
    
    else
    
        result = "";
    
    return result;

【讨论】:

【参考方案2】:

也许写byte ptr就够了

mov bl, byte ptr[edi + edx]    
mov byte ptr[result], bl

此外,您实际上并没有执行空终止。 (+1 wg. Null-Terminierung)

mov byte ptr[result+4], 0

【讨论】:

我用过,然后我什么也没得到(编辑我的帖子)有什么想法吗?

以上是关于Base64 汇编程序填充数组错误“操作数不同大小”Visual Studio的主要内容,如果未能解决你的问题,请参考以下文章

反序列化失败:base-64 字符数组的长度无效

如果输入长度不能被 3 整除,为啥 base64 编码需要填充?

注册许可证出现“输入的不是有效的 Base-64 字符串,因为它包含非 Base-64 字符两个以上的填充字符,或者填充字符间包含非空白字符”

iOS上的Base64编码最后缺少填充

用 JSON Base64 填充 UITableViewCell?

导致此“Base-64 字符数组的长度无效”的原因