将C++x86内联程序集代码转换为C++



我一直在努力将此程序集代码转换为C++代码。

这是一个旧游戏中的函数,它获取像素数据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;
}

非常感谢您的帮助。非常感谢。

它通过将ES设置为DS来保存/恢复ES,因此rep movsd将使用相同的地址进行加载和存储。该指令基本上是memcpy(edi, esi, ecx),但将EDI和ESI中的指针递增4*ecx。https://www.felixcloutier.com/x86/movs:movsb: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的test bx,bx/jnz,即如果BX为零则跳转。所以这是一个while( bx != 0 ) {}循环。有了dec bx,写一个while (--bx)循环是一种低效的方法;编译器会将dec/jnz .top_of_loop放在底部,在循环外进行一次测试,以防需要运行零次。为什么循环总是被编译成";做…而";风格(尾部跳跃(?

有些人会说,这就是while循环在asm中的样子,如果他们想象的是从C到asm的完全天真的翻译。

最新更新