使用AND,OR,SHR和SHL指令以及数组将循环从x86汇编程序转换为C语言

问题描述 投票:1回答:2

我不明白这是什么问题,因为结果正确,但是其中有些错误,我不明白。

1。这是我必须转换为C的x86代码:

%include "io.inc"  
SECTION .data
mask    DD      0xffff, 0xff00ff, 0xf0f0f0f, 0x33333333, 0x55555555

SECTION .text
GLOBAL CMAIN
CMAIN:
    GET_UDEC        4, EAX
    MOV             EBX, mask
    ADD             EBX, 16
    MOV             ECX, 1
.L:
    MOV             ESI, DWORD [EBX]
    MOV             EDI, ESI
    NOT             EDI
    MOV             EDX, EAX
    AND             EAX, ESI
    AND             EDX, EDI
    SHL             EAX, CL
    SHR             EDX, CL
    OR              EAX, EDX
    SHL             ECX, 1
    SUB             EBX, 4
    CMP             EBX, mask - 4
    JNE             .L

    PRINT_UDEC      4, EAX
    NEWLINE
    XOR             EAX, EAX
    RET

2。我转换后的C代码,当我输入0时会输出正确的答案,但是我的代码中有些错误,我不明白这是什么:

#include "stdio.h"
int main(void)
{
    int mask [5] =  {0xffff, 0xff00ff, 0xf0f0f0f, 0x33333333, 0x55555555};


    int eax;
    int esi;
    int ebx;
    int edi;
    int edx;
    char cl = 0;
    scanf("%d",&eax);
    ebx = mask[4];
    ebx = ebx + 16;
    int ecx = 1;
    L:
    esi = ebx;
    edi = esi;
    edi = !edi;
    edx = eax;
    eax = eax && esi;
    edx = edx && edi;
    eax = eax << cl;
    edx = edx >> cl ;
    eax = eax || edx;
    ecx = ecx << 1;
    ebx = ebx - 4;

    if(ebx == mask[1]) //mask - 4
    {
        goto L;
    }

    printf("%d",eax);
    return 0;
}
c assembly x86 nasm reverse-engineering
2个回答
2
投票
if(ebx != mask[1]) //mask - 4
{
    goto L;

}

// JNE暗示一个!=


1
投票

Assembly AND是按位C &,不是逻辑&&。 (与OR相同)。所以你想要eax &= esi

((使用&=“化合物赋值”使C甚至look就像x86样式的2运算符asm,所以我建议这样做。)

也不是按位翻转,不布尔化为0/1。在C中为edi = ~edi;

阅读手册,了解https://www.felixcloutier.com/x86/not之类的x86指令,以及~!之类的C运算符,以检查它们是否不是您想要的。https://en.cppreference.com/w/c/language/expressionshttps://en.cppreference.com/w/c/language/operator_arithmetic

您应该在调试器中单步执行C和asm,以便您注意到first的差异,并知道要修复的指令/ C语句。不要只运行整个过程,而只看一个数字即可得出结果!调试器对于asm非常有用;不要浪费你的时间。


CL是ECX的低字节,而不是单独的C变量。您可以在C中的uint32_tuint8_t之间使用并集,或仅使用eax <<= ecx&31;,因为您没有将CL与ECX分开编写的任何内容。 (x86移位掩盖了它们的计数;该C语句可以编译为shl eax, clhttps://www.felixcloutier.com/x86/sal:sar:shl:shr)。 ECX的低5位也是CL的低5位。

SHR是逻辑右移,不是算术运算,因此至少对于unsigned,您需要使用int而不是>>。但实际上只是将其用于所有内容。


您处理EBX完全错误;这是一个指针。

 MOV             EBX, mask
 ADD             EBX, 16

类似于unsigned int *ebx = mask+4;

dword的大小为4个字节,但是C指针数学运算根据类型的大小进行缩放,因此+1是整个元素,而不是1个字节。因此16个字节是4个双字= 4个unsigned int元素。

MOV             ESI, DWORD [EBX]

这是使用EBX作为地址的负载。如果您在调试器中单步调试asm,这应该很容易看出:这不仅是复制值。

CMP             EBX, mask - 4
JNE             .L

这是NASM语法;它在数组开始之前与dword的address进行比较。实际上,这是一个相当正常的do {} while循环的底部。 (Why are loops always compiled into "do...while" style (tail jump)?

do {          // .L
   ...
} while(ebx != &mask[-1]);    // cmp/jne

它从mask数组的末尾开始循环,当指针经过末尾时停止。

等效地,比较可以是ebx !-= mask - 1。我用一元&(地址)取消了[]来写出来,以明确表示它是数组前一个元素的地址。

请注意,它在not相等时跳跃;您的if()goto向后移动,仅在相等时跳转。这是一个循环。


unsigned mask[]应该为static,因为它在section .data中,而不在堆栈中。而不是const,因为它再次出现在.data中,而不是.rodata(Linux)或.rdata(Windows))

这不影响逻辑,仅影响反编译的细节。


可能还有其他错误;我没有尝试检查所有内容。

© www.soinside.com 2019 - 2024. All rights reserved.