==============================
敬请关注:“固件C字营
==============================
首先思考一个问题,冯洛伊曼架构的计算机如果没有内存,代码能被否正常执行?过程(函数)能不能被相互调用?答案是肯定的,其中的一个实现方法如下。这里只介绍汇编语言的相互调用,如果要用高级语言比如C语言,需要自己实现编译器和ABI才行。
IA-32支持Intel Streaming SIMD Extensions (Intel SSE),不同版本的SSE支持不同的编程模型和指令。SSE支持8个128bit的XMM寄存器,8个64bit MMX寄存器可以在UEFI环境下使用特定的pinsrd/ pinsrw/ pshufd/movd指令在通用寄存器之间传递数据,进而可以把XMM、MMX寄存器当做普通32bit数据暂存器来使用。如此,我们就可以在堆栈没有准备好的情况下使用JMP跳转指令来模拟一般的call/ret方式调用子过程。
128bit的XMM寄存器可以被拆分成4个slot,分别与通用寄存器(如:EAX)进行数据传递,参考实现如下。
XMM7:EBP - slot 0, EBX - slot 1, ESI - slot 2, EDI - slot 3
XMM6:ESP - slot 0, EAX - slot 1, EDX - slot 2, ECX - slot 3
XMM5:slot 0 for calling stack,slot 1 for uCode status
MM0: BIST State
MM5: Save time-stamp counter value high32bit
MM6: Save time-stamp counter value low32bit.
MM7: calling stack
例1:
子过程Function是需要被调用的过程,在堆栈还没有准备好的情况下,可以使用如下代码来实现,只要在Function内部保持通用寄存器不被修改(具体方法是把通用寄存器保存在MMX和XMM寄存器当中)就可以保证Function的调用不会破坏执行环境。
CALL_MMX Function ;调用子过程,返回地址保存在MM7寄存器
RET_ESI ;返回到主过程
例2:
其中SXMMN和LXMMN宏分别为存储和读取ReturnAddress即调用CALL_XMM指令之后的下一条指令的地址。
CALL_XMM Function ;调用子过程,返回地址保存在XMM5-Slot0寄存器
RET_XMM ;返回到主过程
例3:同理我们也可以使用ebp暂存过程返回地址。
更多导读,尽情期待!
==============================
敬请猛戳下面链接,关注&转发
敬请关注we-hat“:“固件C字营”
点击左下角“分享”,快乐更多人
==============================
we-chat“固件C字营”