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.
CLD in interrupt handlers
Re: CLD in interrupt handlers
Hi,
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
This depends on the ABI used by any functions/routines that are called by the interrupt handler's code.jnc100 wrote:Do we need to update Interrupt Service Routines to include CLD as part of the prolog or am I missing something obvious?
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.
Re: CLD in interrupt handlers
If we are casting our votes, I choose "yes". Having that instruction with a good comment line will point out the importance of this.
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".
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.Brendan wrote:It's possible for an ABI to say "direction flag is undefined"
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".
Re: CLD in interrupt handlers
Hi,
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 "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.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.
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.Brendan wrote:It's possible for an ABI to say "direction flag is undefined"
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 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.
Re: CLD in interrupt handlers
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.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.
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.