如何将 REP STOS 转换为 C 代码

6

我已经调试了REP STOS DWORD PTR ES:[EDI]一段时间了。

我的结论是它总是使用

ECX作为计数器。 EAX作为将被复制到EDI并追加ECX次的值。 因此,在输入EDI指向的转储后,它似乎会覆盖指向的数据。

它似乎总是只使用ECX作为计数器,同时通过4个字节更改EDI。 当计数器达到0时,它停止工作。

所以我想出了这样的代码:

while(regs.d.ecx != 0)
{
    *(unsigned int *)(regs.d.edi) = regs.d.eax;
    regs.d.edi += 4;
    regs.d.ecx--;
}

看起来是可以工作的...但我还是有点担心,因为我只是靠运气和猜测做到的。这是否可靠?比如计数器总是ECX,数据总是EAX,并且它总是复制4个字节而不是更少吗?


1
发现一个重复的https://dev59.com/km865IYBdhLWcg3wa-A0有点晚了..看起来一切都是有效的。 - SSpoke
1
我建议您获取AMD的程序员手册(第1卷介绍,第3卷通用指令),以及英特尔的手册。不知何故,我更喜欢AMD的结构和表格。英特尔的似乎更详细一些。 - Alexey Frunze
1个回答

11
你的答案基本正确。唯一的区别在于方向标志(DF)控制4是加还是减EDI(实际上它是相对于ES段基址偏移,但你可能不关心这个):
for (; regs.d.ecx != 0; regs.d.ecx--)
{
    *(unsigned int *)(regs.d.edi) = regs.d.eax;
    regs.d.edi += regs.eflags.df ? -4 : 4;
}

请注意,for (; regs.d.ecx != 0; regs.d.ecx--) { }REP前缀的操作,循环体是STOS DWORD...的操作。
由于你提了这么多问题,我认为Intel 64和IA-32架构软件开发人员手册,卷2A和2B会对你有所帮助。其中包含每个指令和前缀的描述,包括伪代码描述。

1
不仅仅是DF。根据CPU模式,STOSD可能需要操作数大小前缀(66h),它控制元素大小(16位与32位,还有AX与EAX),地址大小前缀(67h),它控制使用EDI和ECX的位数(16位与32位)。最后,它使用ES段寄存器,这意味着虚拟地址为ES.base + (E)DI。哦,当然,如果内存无法写入(只读或未映射或特权级别(CPL&RPL)对于段或底层页面不足,如果启用了页转换,则可能会引发异常)。 :) - Alexey Frunze
我甚至不理解这些标志是如何从中生成的...我的模拟器甚至没有标志...到目前为止一切都很好!:P,希望堆栈和寄存器足够。 - SSpoke
@SSpoke: EFLAGS 可以被建模为另一个寄存器,其中一些位由其他指令设置。对于 DF 标志,有特定的指令 - STD 设置它,而 CLD 清除它。 - caf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接