翻译C++ x86内联汇编代码为c++

发布于 2025-01-21 05:53:01 字数 1240 浏览 2 评论 0原文

我一直在努力将此装配代码转换为C ++代码。

这是一个旧游戏的函数,该功能采用Pixel Data 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;
    };
}

这是我到达的地方:当然,是否正确),

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

    }
    
    ++stmp;

    dtmp += size;

    --j;
}

非常感谢任何帮助。谢谢。

I've been struggling trying to convert this assembly code to C++ code.

It's a function from an old game that takes pixel data Stmp, and I believe it places it to destination 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

热鲨 2025-01-28 05:53:01

它保存/还原设置等于DS MOVSD 将使用相同的地址进行负载和存储。该指令基本上是memcpy(EDI,ESI,ECX),但会增加EDI和ESI中的指针(由4 * ECX)。 movsw:movsd:movsq

在平坦的内存模型中,您可以完全忽略它。该代码看起来可能已经写成以16位虚幻模式或甚至实际模式运行,因此到处都有16位寄存器的使用。


看起来像是加载了某种记录,这些记录要阐明要复制多少个字节,并读取直到记录结束,此时它会在其中查找下一个记录。周围有一个外循环,通过记录循环。

我认为的记录看起来像:

  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.
   };

内部循环是:

 ;;  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

旧的CPU(ivybridge之前)的rep movsdrep movsb更快,否则此代码只能做到这一点。

        or      bx,bx;
        jz      exit_1;

这是一个过时的成语,来自8080,用于测试BX,BX/JNZ,即如果Bx为零,则跳转。因此,它是while(bx!= 0){}循环。使用DEC BX。这是编写的一种低效方法,而(-bx) loop;编译器会将DEC/JNZ .TOP_OF_LOOP放在底部,一次测试在循环外面一次,以防其运行零次。 Why are loops always compiled into "do.. 。

It saves / restores ES around setting it equal to DS so rep movsd will use the same addresses for load and store. That instruction is basically memcpy(edi, esi, ecx) but incrementing the pointers in EDI and ESI (by 4 * ecx). https://www.felixcloutier.com/x86/movs:movsb:movsw:movsd:movsq

In a flat memory model, you can totally ignore that. 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.


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.

        or      bx,bx;
        jz      exit_1;

That's an obsolete idiom that comes from 8080 for test bx,bx / jnz, i.e. jump if BX was zero. So it's a while( bx != 0 ) {} loop. With dec bx in it. It's an inefficient way to write a while (--bx) loop; 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. Why are loops always compiled into "do...while" style (tail jump)?

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文