我需要生成一个跳转指令来跳转到另一个ISR(中断服务程序)。我正在开发一个32位FreeDOS应用程序。
在阅读了OW手册(cguide.pdf和clr.pdf)后,我想出了成功编译的两种方式,没有任何警告或错误。
/* Code Snippet #1 */
#pragma aux old08 aborts ;
void (__interrupt __far *old08)(void); // function pointer declaration
void __interrupt __far new08(void) {
/* Do some processing here ... */
(*old08)(); /* OW will now generate a jump inst. instead of call*/
}
我想出的另一种方法是:
/* Code Snippet #2 */
static void jumpToOld08(void);
# pragma aux jumpToOld08 = \
".686p" \
" DB 0xEA" \
"off_old08 DD 0" \
"sel_old08 DW 0" ;
void __interrupt __far new08(void){
/* Do some processing here ... */
jumpToOld08();
}
extern unsigned short sel_old08;
extern unsigned int off_old08;
sel_old08 = ( __segment )FP_SEG(old08);
off_old08 = FP_OFF(old08);
现在我的问题是以上两种方式中哪一种更正确或更好?任何想法或意见?
还有其他方法可以实现这一目标吗?
答案 0 :(得分:2)
interrupt
函数总是很远。
就指令本身而言,你手动构建的远跳是正确的,但是,我敢打赌,只是跳转(而不是调用)不会删除先前由new08()
保存在堆栈上的东西。序言(这可能是很多寄存器,最重要的是,还有你的old08()
必须归还的返回地址!)。
为什么这么有创意?
答案 1 :(得分:0)
#include <dos.h>
void _chain_intr( void (__interrupt __far *func)(void) );
此函数可用于跳转到链中的另一个中断处理程序。此功能永不返回。它弹出 interrupt 关键字保存的所有寄存器并跳转到处理程序。当 func 指定的中断处理程序接收到控制权时,堆栈和寄存器就像中断刚好发生一样。
此函数只能在使用 interrupt 关键字声明的函数中使用。
跳而不是调用的优势在irq处理程序中并不明显,但绝对适用于软件中断处理程序。链中的下一个软件中断处理程序期望cpu寄存器包含一些信息,例如传递给它的参数,因此在跳转到下一个处理程序之前 chainintr 恢复所有cpu寄存器,好像下一个处理程序直接接收控件一样。
答案 2 :(得分:0)
我可能会写这样的东西:
void far_jump (uint32_t offset, uint16_t selector)
{
/* remove the (callee's) stack frame including the return address by manipulating esp & ebp */
/* the top of the stack now points to offset:selector */
_asm
{
retf ; or whatever the asm syntax dictates
}
/* esp & ebp will now point to the caller's stack frame */
}
我记得32位模式会将选择器推送到32位单元,即使只使用了低16位。