CLD in interrupt handlers

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

CLD in interrupt handlers

Post by jnc100 »

Following on from a recent question where the need for DF to be clear on function entry and exit was highlighted (as per sysV 386 ABI), I've been thinking about interrupt handlers. Suppose a user program sets DF to 1 during a function, then an interrupt happens which calls C code. As far as I can see, the interrupt call process won't affect the DF flag (Intel 3A states EFLAGS is pushed, TF/VM/RF/NT alone are cleared) and so the C code will erroneously run with DF set.

Do we need to update Interrupt Service Routines to include CLD as part of the prolog or am I missing something obvious?

Regards,
John.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: CLD in interrupt handlers

Post by Brendan »

Hi,
jnc100 wrote:Do we need to update Interrupt Service Routines to include CLD as part of the prolog or am I missing something obvious?
This depends on the ABI used by any functions/routines that are called by the interrupt handler's code.

Most (all) well-known ABIs say "direction flag is clear". In that case your ISRs (and anything else where control may have been transferred from a "less trusted" piece of code - e.g. the kernel's SYSCALL, SYSENTER or call gate entry points) need to put the direction flag in its default state to uphold the ABI before calling code that relies on the ABI.

It's possible for an ABI to say "direction flag is undefined" (e.g. if you're inventing your own ABI and/or using assembly language). In that case there's no need for ISRs (or other things) to put the direction flag in its default state before calling code that relies on the ABI.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: CLD in interrupt handlers

Post by Antti »

If we are casting our votes, I choose "yes". Having that instruction with a good comment line will point out the importance of this.
Brendan wrote:It's possible for an ABI to say "direction flag is undefined"
If we defined the flag only when it is needed, e.g. "cld; rep stosb; rep movsb", we could avoid flipping it unnecessarily although its overhead is negligible. If we are using the SYSCALL instruction, it is easy to mask that bit so its overhead is less than negligible.

Anyway, I think it may still be better to have it undefined. It could cause serious data corruction if the flag was not defined as it should be. Defining the bit just before it is needed is an easy way to avoid this problem. This is a practical advantage. However, I would not be surprised if there were some hidden bugs somewhere (operating systems, compilers) that are hidden only because "the direction flag is likely to be clear even if we have not explicitly defined it".
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: CLD in interrupt handlers

Post by Brendan »

Hi,
Antti wrote:If we are casting our votes, I choose "yes". Having that instruction with a good comment line will point out the importance of this.
Brendan wrote:It's possible for an ABI to say "direction flag is undefined"
If we defined the flag only when it is needed, e.g. "cld; rep stosb; rep movsb", we could avoid flipping it unnecessarily although its overhead is negligible. If we are using the SYSCALL instruction, it is easy to mask that bit so its overhead is less than negligible.

Anyway, I think it may still be better to have it undefined. It could cause serious data corruction if the flag was not defined as it should be. Defining the bit just before it is needed is an easy way to avoid this problem. This is a practical advantage. However, I would not be surprised if there were some hidden bugs somewhere (operating systems, compilers) that are hidden only because "the direction flag is likely to be clear even if we have not explicitly defined it".
For "direction flag clear by default", the worst case is multiple functions (e.g. "A calls B which calls C ...") that all want carry flag set, and you end up with a STD and a CLD for each function.

For "direction flag unknown by default", the worst case is one extra CLD or STD per function in every function that uses the CPU's string instructions.

However...

For "direction flag clear by default", the best case is that everything wants the direction flag clear, and you end up with no STD or CLD instructions at all. For "direction flag unknown by default" the best case is the same as the worst case.

The typical case is between these extremes, but it's much closer to the best case (few functions actually use the string instructions or depend on the direction flag, and most that do want it clear). This mostly implies that in general, "direction flag clear by default" is likely to be a better policy.

However...

For absolute best quality code, you'd want a compiler/optimiser that (e.g.) analyses the call graph while keeping track of the state of the direction flag, that ensures that CLD and STD instructions are only used where absolutely necessary. This would give "better or equal" quality code than any other approach. Of course compilers are complex and the time spent to add support for direction flag optimisations is likely better spent improving optimisation in other areas.

:)


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: CLD in interrupt handlers

Post by jnc100 »

Brendan wrote:For absolute best quality code, you'd want a compiler/optimiser that (e.g.) analyses the call graph while keeping track of the state of the direction flag, that ensures that CLD and STD instructions are only used where absolutely necessary. This would give "better or equal" quality code than any other approach. Of course compilers are complex and the time spent to add support for direction flag optimisations is likely better spent improving optimisation in other areas.
This is problematic to implement, especially for interrupts as you cannot guarantee where in the code an interrupt will occur, so DF may be either set or cleared. You could analyse the called handler chain to see if it actually matters (i.e. if string instructions are used or not) and then conditionally clear DF in the asm stub, but this would require close interaction between your compiler and assembler. Also, particularly with shared interrupts, a chain of handlers may be called and it is difficult or impossible to know at compile time what the exact call graph will be as it also depends on what hardware is installed on the users system.

I think I'll just add a cld instruction to the wiki page for now. This assumes that the vast majority of people following it will be using the gcc cross compiler and the sysV 386 abi, and will therefore help avoid difficult to debug errors in the future. We do, however, also break the abi in other ways, for example not ensuring that the floating point registers are zero or not saving sse state. These issues are for the most part though avoided by the use of compiler flags.

Regards,
John.
Post Reply