对于大学作业,我的任务是使用x86-64中的汇编代码覆盖Divide-By-Zero中断处理程序,以使除法运算结果为被除数-1。
因此,据我了解,我需要在返回程序之前更改除法寄存器的值。
如何获得程序的原始寄存器值并进行更改?它们存储在哪里?
中断/异常仅将CS:RIP,RFLAGS和用户空间SS:RSP保存在异常帧本身中。所有其他寄存器值均未修改。x86不像其他ISA那样注册组切换。
中断处理程序必须保存/恢复他们要使用的每个寄存器,以确保它们不修改用户空间状态。你需要使用它来获得几个暂存寄存器(除非你进行多个假设并且仅支持一个操作数大小和指令长度),但是要修改的用户空间状态部分仍在寄存器中。
幸运的是,取决于除法指令https://www.felixcloutier.com/的操作数大小,股息位于固定位置,即AH:AL(又名AX),DX:AX,EDX:EAX或RDX:RAX。x86 / idiv或div
。(或者,如果你包含16/32位兼容模式用户空间,则也可能仅是AL aam imm8
)
因此,你不必解码寻址模式,只需解码前缀和操作码即可确定实际涉及RDX和RAX的哪些部分。
但是要在除法指令之后返回RIP指针,实际上你需要确定指令长度,例如2字节div ecx
vs. div word [rdi + r10*2 + 256]
(9字节:REX和操作数大小的前缀,操作码,modrm + SIB + disp32)。
你确实知道该长度小于15个字节(包括可能的冗余前缀),否则它将以#UD而不是#DE出现错误。
在最坏的情况下,可能存在多余或无意义的前缀,将指令的大小扩展到15个字节的限制。
@RossRidge:是的,我并不是要说最大为9个字节。仅举两个例子。我没有包含都可以非冗余使用的REX或地址大小。糟糕,但是我在寻址模式中包括了RDX,我应该更改它。而且可能也没有使它看起来像我在尝试显示最极端的示例。
我只是想让原始海报更加清晰,这说明了完整的指令解码是什么。
@RossRidge:好的。我没有在第一次编辑中提到它,因为不需要强制执行或检测到该限制,而且显而易见的实现(通过前缀循环直到操作码)应该可以正常工作。如果我没记错的话,没有前缀会影响其余说明的长度,因此您甚至无需记录所见内容。(设计了ModRM开头,因此长度查找不需要考虑来自REX的额外寄存器位,这使得R12和R13作为基址寄存器可能会变得更糟。)