Page 1 of 1

Extern "C" and inline assembly - A solution for ISRs on GCC?

Posted: Wed Aug 20, 2014 6:04 pm
by lordio
I noticed the wiki explains that GCC doesn't have a way to make "naked" functions (without the normal function bounding instructions, enter, leave, and ret) for ISRs on x86. I wonder if I've discovered something novel in that case, though I hardly expect so.

Declare an extern "C" method,

Code: Select all

extern "C" void interrupt_handler();
then, in an assembly block,

Code: Select all

asm("interrupt_handler:\n
  call actual_handler\n
  iret");
Obviously, the method actual_handler will also have to be declared extern "C", and defined elsewhere in the kernel. One could further parameterize actual_handler according to their ABI.

Is this what people already use, and I just thought I devised it myself? Do people normally split the implementation into its own assembly source file? That would make sense for a more realistic ISR, probably -- one that takes note of its environment before calling into the kernel.

Re: Extern "C" and inline assembly - A solution for ISRs on

Posted: Wed Aug 20, 2014 7:59 pm
by bluemoon
1. you did not preserve registers.
2. You gain nothing on the resulting binary, by putting the assembly stub within inline assembly.
3. You need to deal with non-trivial problems like optimization and non standard behaviours: you hijack a function to create another function, both the hosting function and inline asm block may get optimized away, or otherwise get hidden visibility

In short, you should just put the assembly stub in an assembly file.

Re: Extern "C" and inline assembly - A solution for ISRs on

Posted: Thu Aug 21, 2014 7:26 am
by lordio
bluemoon wrote:1. you did not preserve registers.
Looking at my copy of the System V ABI (to which GCC adheres), and for AMD64, this would be all the GPRs other than rbp, rbx, and r12-r15?
bluemoon wrote:2. You gain nothing on the resulting binary, by putting the assembly stub within inline assembly.
Expected. It was kind of born of laziness anyway, with the admittedly flimsy excuse of source locality, rather than any machine-code benefit.
bluemoon wrote:3. You need to deal with non-trivial problems like optimization and non standard behaviours: you hijack a function to create another function, both the hosting function and inline asm block may get optimized away, or otherwise get hidden visibility
Even if a pointer to the function is used, in the kernel, as part of IDT initialization? I guess since GCC will probably notice it's not used directly in the source, that makes sense.

Also, for better or worse, and probably in a lot of places where it's not needed, I've been marking inline assembly blocks as volatile. From my reading of GCC's manual, it could still remove the block as unreachable, so I guess this is revealed as the hacky solution that it is.
bluemoon wrote:In short, you should just put the assembly stub in an assembly file.
Looks that way. Thanks for weighing in.

Re: Extern "C" and inline assembly - A solution for ISRs on

Posted: Thu Aug 21, 2014 7:53 am
by bluemoon
lordio wrote:
bluemoon wrote:1. you did not preserve registers.
Looking at my copy of the System V ABI (to which GCC adheres), and for AMD64, this would be all the GPRs other than rbp, rbx, and r12-r15?
You could define you own ABI for kernel call and decide what should be preserved, and who (kernel or user-space stub) preserve them.
But the general idea is that you should preserve everything for interrupts, but you could do less with syscall.
lordio wrote:Also, for better or worse, and probably in a lot of places where it's not needed, I've been marking inline assembly blocks as volatile.
Do not abuse the volatile keyword.
You should also read this.

Re: Extern "C" and inline assembly - A solution for ISRs on

Posted: Thu Aug 21, 2014 8:08 am
by lordio
bluemoon wrote:You could define you own ABI for kernel call and decide what should be preserved, and who (kernel or user-space stub) preserve them.
But the general idea is that you should preserve everything for interrupts, but you could do less with syscall.
Well, I plan to only support syscall/sysret for direct kernel calls (no "int 80h" like Linux still supports), and I understand and accept that I'll have to define my ABI there. I referred to the System V spec only as far as parameter passing for methods, which is significant for the C++ portions of my kernel.
bluemoon wrote:Do not abuse the volatile keyword.
You should also read this.
Yikes. I can see what he was trying to do, but still. Duly noted.