简体   繁体   English

将 C++ x86 内联汇编代码翻译成 C++

[英]Translating C++ x86 Inline assembly code to C++

I've been struggling trying to convert this assembly code to C++ code.我一直在努力尝试将此汇编代码转换为 C++ 代码。

It's a function from an old game that takes pixel data Stmp , and I believe it places it to destination void* dest这是一个来自旧游戏的 function,它采用像素数据Stmp ,我相信它将它放置到目的地void* dest

void Function(int x, int y, int yl, void* Stmp, void* dest)
{
    unsigned long size = 1280 * 2;
    unsigned long j = yl;
    void* Dtmp = (void*)((char*)dest + y * size + (x * 2));

    _asm
    {
        push    es;

        push    ds;
        pop     es;

        mov     edx,Dtmp;
        mov     esi,Stmp;

        mov     ebx,j;

        xor     eax,eax;
        xor     ecx,ecx;
    loop_1:
        or      bx,bx;
        jz      exit_1;
        mov     edi,edx;

    loop_2:
        cmp     word ptr[esi],0xffff;
        jz      exit_2;

        mov     ax,[esi];
        add     edi,eax;

        mov     cx,[esi+2];
        add     esi,4;

        shr     ecx,2;
        jnc     Next2;
        movsw;
    Next2:
        rep     movsd;

        jmp     loop_2;
    exit_2:
        add     esi,2;

        add     edx,size;
        dec     bx;
        jmp     loop_1;
    exit_1:
        pop     es;
    };
}

That's where I've gotten as far to: (Not sure if it's even correct)那就是我到目前为止的地方:(不确定它是否正确)

while (j > 0)
{
    if (*stmp != 0xffff) 
    {

    }
    
    ++stmp;

    dtmp += size;

    --j;
}

Any help is greatly appreciated.任何帮助是极大的赞赏。 Thank you.谢谢你。

It saves / restores ES around setting it equal to DS so rep movsd will use the same addresses for load and store.它在将 ES 设置为等于 DS 时保存/恢复 ES,因此rep movsd将使用相同的地址进行加载和存储。 That instruction is basically memcpy(edi, esi, ecx) but incrementing the pointers in EDI and ESI (by 4 * ecx).该指令基本上是memcpy(edi, esi, ecx)但增加了 EDI 和 ESI 中的指针(4 * ecx)。 https://www.felixcloutier.com/x86/movs:movsb:movsw:movsd:movsq https://www.felixcloutier.com/x86/movs:movsb:movsw:movsd:movsq

In a flat memory model, you can totally ignore that.在一个平面 memory model,你完全可以忽略它。 This code looks like it might have been written to run in 16-bit unreal mode, or possibly even real mode, hence the use of 16-bit registers all over the place.这段代码看起来可能是为在 16 位虚幻模式下运行而编写的,甚至可能是实模式,因此到处都使用 16 位寄存器。


Look like it's loading some kind of records that tell it how many bytes to copy, and reading until the end of the record, at which point it looks for the next record there.看起来它正在加载某种记录,告诉它要复制多少字节,并读取直到记录结束,此时它在那里寻找下一条记录。 There's an outer loop around that, looping through records.围绕它有一个外部循环,循环遍历记录。

The records look like this I think:我认为记录看起来像这样:

  struct sprite_line {
     uint16_t skip_dstbytes, src_bytes;
     uint16_t src_data[];        // flexible array member, actual size unlimited but assumed to be a multiple of 2.
   };

The inner loop is this:内循环是这样的:

 ;;  char *dstp;  // in EDI
 ;;  struct spriteline *p  // in ESI

    loop_2:
        cmp     word ptr[esi],0xffff  ; while( p->skip_dstbytes != (uint16_t)-1 ) {

        jz      exit_2;

        mov     ax,[esi];             ; EAX was xor-zeroed earlier; some old CPUs maybe had slow movzx loads
        add     edi,eax;              ; dstp += p->skip_dstbytes;

        mov     cx,[esi+2];           ; bytelen = p->src_len;
        add     esi,4;                ; p->data

        shr     ecx,2;                ; length in dwords = bytelen >> 2
        jnc     Next2;
        movsw;                        ; one 16-bit (word) copy if bytelen >> 1 is odd, i.e. if last bit shifted out was a 1.
            ;  The first bit shifted out isn't checked, so size is assumed to be a multiple of 2.
    Next2:
        rep     movsd;                ; copy in 4-byte chunks

Old CPUs (before IvyBridge) had rep movsd faster than rep movsb , otherwise this code could just have done that.旧 CPU(在 IvyBridge 之前)的rep movsdrep movsb快,否则这段代码就可以做到这一点。

        or      bx,bx;
        jz      exit_1;

That's an obsolete idiom that comes from 8080 for test bx,bx / jnz , ie jump if BX was zero.这是来自 8080 的一个过时的习语,用于test bx,bx / jnz ,即如果 BX 为零则跳转。 So it's a while( bx != 0 ) {} loop.所以这是一个while( bx != 0 ) {}循环。 With dec bx in it.里面有dec bx It's an inefficient way to write a while (--bx) loop;这是编写while (--bx)循环的低效方法; a compiler would put a dec / jnz.top_of_loop at the bottom, with a test once outside the loop in case it needs to run zero times.编译器会将dec / jnz.top_of_loop放在底部,并在循环外进行一次测试,以防它需要运行零次。 Why are loops always compiled into "do...while" style (tail jump)? 为什么循环总是编译成“do...while”风格(尾部跳转)?

Some people would say that's what a while loop looks like in asm, if they're picturing totally naive translation from C to asm.有些人会说这就是while循环在 asm 中的样子,如果他们想象的是从 C 到 asm 的完全天真的翻译。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM