abrash-black-book/11-08.html
2013-12-30 12:21:49 +11:00

136 lines
7.5 KiB
HTML

<HTML>
<HEAD>
<META name=vsisbn content="1576101746">
<META name=vstitle content="Michael Abrash's Graphics Programming Black Book, Special Edition">
<META name=vsauthor content="Michael Abrash">
<META name=vspublisher content="The Coriolis Group">
<META name=vspubdate content="07/01/97">
<META name=vscategory content="Web and Software Development: Game Development,Web and Software Development: Graphics and Multimedia Development">
<TITLE>Michael Abrash's Graphics Programming Black Book Special Edition: Pushing the 286 and 386</TITLE>
<!-- HEADER -->
<!-- Empty Reference Subhead -->
<!--ISBN=1576101746//-->
<!--TITLE=Michael Abrash's Graphics Programming Black Book Special Edition//-->
<!--AUTHOR=Michael Abrash//-->
<!--PUBLISHER=The Coriolis Group, Inc.//-->
<!--CHAPTER=11//-->
<!--PAGES=226-231//-->
<!--UNASSIGNED1//-->
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="11-07.html">Previous</A></TD>
<TD><A HREF="index.html">Table of Contents</A></TD>
<TD><A HREF="12-01.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<P><BR></P>
<P>Well, there&#146;s only one instruction other than <B>POPF</B> that loads the FLAGS register directly from the stack, and that&#146;s <B>IRET</B>, which loads the FLAGS register from the stack as it branches, as shown in Figure 11.5. iret has no known bugs of the sort that plague <B>POPF</B>, so it&#146;s certainly a candidate to replace popf in non-interruptible applications. Unfortunately, <B>IRET</B> loads the FLAGS register with the <I>third</I> word down on the stack, not the word on top of the stack, as is the case with <B>POPF</B>; the far return address that <B>IRET</B> pops into CS:IP lies between the top of the stack and the word popped into the FLAGS register.</P>
<P>Obviously, the segment:offset that <B>IRET</B> expects to find on the stack above the pushed flags isn&#146;t present when the stack is set up for <B>POPF</B>, so we&#146;ll have to adjust the stack a bit before we can substitute <B>IRET</B> for <B>POPF</B>. What we&#146;ll have to do is push the segment:offset of the instruction after our workaround code onto the stack right above the pushed flags. <B>IRET</B> will then branch to that address and pop the flags, ending up at the instruction after the workaround code with the flags popped. That&#146;s just the result that would have occurred had we executed <B>POPF</B>&#151;WITH the bonus that no interrupts can accidentally occur when the Interrupt flag is 0 both before and after the pop.</P>
<P><A NAME="Fig4"><!-- </A><A HREF="javascript:displayWindow('images/11-04.jpg',412,383 )"> --><IMG SRC="images/11-04.jpg"><BR><!-- </A>
<BR><A HREF="javascript:displayWindow('images/11-04.jpg',412,383)"> --><FONT COLOR="#000077"><B>Figure 11.4</B></FONT></A>&nbsp;&nbsp;<I>The operation of POPF.</I>
</P>
<P>How can we push the segment:offset of the next instruction? Well, finding the offset of the next instruction by performing a near call to that instruction is a tried-and-true trick. We can do something similar here, but in this case we need a far call, since <B>IRET</B> requires both a segment and an offset. We&#146;ll also branch backward so that the address pushed on the stack will point to the instruction we want to continue with. The code works out like this:</P>
<!-- CODE //-->
<PRE>
jmpshort popfskip
popfiret:
iret; branches to the instruction after the
; call, popping the word below the address
; pushed by CALL into the FLAGS register
popfskip:
call far ptr popfiret
;pushes the segment:offset of the next
; instruction on the stack just above
; the flags word, setting things up so
; that IRET will branch to the next
; instruction and pop the flags
; When execution reaches the instruction following this comment,
; the word that was on top of the stack when JMP SHORT POPFSKIP
; was reached has been popped into the FLAGS register, just as
; if a POPF instruction had been executed.
</PRE>
<!-- END CODE //-->
<P><A NAME="Fig5"><!-- </A><A HREF="javascript:displayWindow('images/11-05.jpg',410,520 )"> --><IMG SRC="images/11-05.jpg"><BR><!-- </A>
<BR><A HREF="javascript:displayWindow('images/11-05.jpg',410,520)"> --><FONT COLOR="#000077"><B>Figure 11.5</B></FONT></A>&nbsp;&nbsp;<I>The operation of IRET.</I>
</P>
<P>The operation of this code is illustrated in Figure 11.6.
</P>
<P>The <B>POPF</B> workaround can best be implemented as a macro; we can also emulate a far call by pushing CS and performing a near call, thereby shrinking the workaround code by 1 byte:</P>
<!-- CODE //-->
<PRE>
EMULATE_POPF macro
local popfskip, popfiret
jmp short popfskip
popfiret:
iret
popfskip:
push cs
call popfiret
endm
</PRE>
<!-- END CODE //-->
<P>By the way, the flags can be popped much more quickly if you&#146;re willing to alter a register in the process. For example, the following macro emulates <B>POPF</B> with just one branch, but wipes out AX:</P>
<!-- CODE SNIP //-->
<PRE>
EMULATE_POPF_TRASH_AX macro
push cs
mov ax,offset $&#43;5
push ax
iret
endm
</PRE>
<!-- END CODE SNIP //-->
<P>It&#146;s not a perfect substitute for <B>POPF</B>, since <B>POPF</B> doesn&#146;t alter any registers, but it&#146;s faster and shorter than <B>EMULATE_POPF</B> when you can spare the register. If you&#146;re using 286-specific instructions, you can use which is shorter still, alters no registers, and branches just once. (Of course, this version of <B>EMULATE_POPF</B> won&#146;t work on an 8088.)</P>
<!-- CODE SNIP //-->
<PRE>
.286
:
EMULATE_POPFmacro
pushcs
pushoffset $&#43;4
iret
endm
</PRE>
<!-- END CODE SNIP //-->
<P><A NAME="Fig6"><!-- </A><A HREF="javascript:displayWindow('images/11-06.jpg',409,447 )"> --><IMG SRC="images/11-06.jpg"><BR><!-- </A>
<BR><A HREF="javascript:displayWindow('images/11-06.jpg',409,447)"> --><FONT COLOR="#000077"><B>Figure 11.6</B></FONT></A>&nbsp;&nbsp;<I>Workaround code for the POPF bug.</I>
</P>
<P>The standard version of <B>EMULATE_POPF</B> is 6 bytes longer than <B>POPF</B> and much slower, as you&#146;d expect given that it involves three branches. Anyone in his/her right mind would prefer <B>POPF</B> to a larger, slower, three-branch macro&#151;given a choice. In noncode, however, there&#146;s no choice here; the safer&#151;if slower&#151;approach is the best. (Having people associate your programs with crashed computers is <I>not</I> a desirable situation, no matter how unfair the circumstances under which it occurs.)</P>
<P>And now you know the nature of and the workaround for the <B>POPF</B> bug. Whether you ever need the workaround or not, it&#146;s a neatly packaged example of the tremendous flexibility of the x86 instruction set.</P><P><BR></P>
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="11-07.html">Previous</A></TD>
<TD><A HREF="index.html">Table of Contents</A></TD>
<TD><A HREF="12-01.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<hr width="90%" size="1" noshade>
<div align="center">
<font face="Verdana,sans-serif" size="1">Graphics Programming Black Book &copy; 2001 Michael Abrash</font>
</div>
<!-- all of the reference materials (books) have the footer and subfoot reveresed -->
<!-- reference_subfoot = footer -->
<!-- reference_footer = subfoot -->
<!-- BEGIN SUB FOOTER -->
</BODY>
</HTML>
<!-- END FOOTER -->