4

I apologize if this should sound trivial and unsubtle but I couldn't figure out an intuitive way to google it, Why are some kernel actions like saving the current state of the registers and the stack(just to mention a few) written in Assembly? Why can't they be written in C because after all, presumably, when compilation is done, all we get is object code? Besides when you use ollydbg, you notice that before a function call(in C), the current state of the register is pushed to the stack

  • 5
    Because there's no way to express this in C? Simple as that... (C is an abstraction from the hardware) –  Jul 18 '17 at 08:36
  • 5
    C is a high-level language and as this hardware-agnostic. To manipulate registers, you have to _have_ an architecture with registers, which is not a prerequisite for programming it in the language c. – Ctx Jul 18 '17 at 08:38
  • 'you notice that before a function call(in C), the current state of the register is pushed to the stack' some general-purpose registers may be pushed as required, but that is not the whole deal on most architectures. Example: if a process context needs to be swapped out, then the memory-management hardware registers need to be swapped out as well. – Martin James Jul 18 '17 at 08:40
  • Hi, There is no direct way of writing this in C, because `presumably, when compilation is done, all we get is object code` it generates its own callee save and caller save instructions which might not be the one you needed in kernel operations, and moreover the kind of control you get with assembly. – NishanthSpShetty Jul 18 '17 at 08:41
  • So in a nutshell there is just no way the equivalent routines for saving the state of the registers in Assembly can be achieved in C? – Clinton Kavai Jul 18 '17 at 08:55
  • @Clinton Chogo - you can use thee inline assembly functions - but you need to know the processor instructions mnemonics & how they work anyway. Writing the low level part of any system requires a deep knowledge of the hardware – 0___________ Jul 18 '17 at 09:17

5 Answers5

4

When writing an OS the main goal is to maintain the highest abstraction to make the code reusable on different architectures, but at the end inevitably there is the architecture.

Each machine performs the very low level functions in such a specialized way that no general programming language can sustain.

Task switching, bus control, device interrupt handling, just to name few, cannot be coded efficiently using an high level language (consider instruction sequences, involved registers, and eventual critical CPU timings and priority levels).

On the other hand, it is not even convenient to use mixed programming, i.e. inline assembler, because the crafted module will be no more abstract, containing specific architecture code that can't be reused.

The common solution is to write all code following the highest abstraction level, reducing to a few modules the specialized code. These routines, fully written in assembly, are normally well defined in terms of supplied input and expected output, so the programmer can produce same results on different architectures.

Compiling for different CPU is then done by simply switching the set of assembly routines.

Frankie_C
  • 4,764
  • 1
  • 13
  • 30
2

C does not assure you that it modifies the registers you need to modify.

C just implements a logic you write in your code and the interpretation given by the language will be as you expect, hiding completely the details behind the interpretation.

If you want a kind of logic like set the X register with a given value or move data from register X to register Y, as it's necessary to do in kernel sometimes, this kind of logic is not defined by the C language.

alinsoar
  • 15,386
  • 4
  • 57
  • 74
1

C is a generic high level language, not specific to one target. But at the kernel level there are things that you need to do that are target specific that the C language simply cannot do. Enabling an interrupt or configuring an MMU or configuring something to do with the protection mechanism. On some targets these items and others are configured using registers in the address space but on some targets specific assembly language instructions are required and so C cannot be used, it has to be assembly. There is usually at least one thing you have to use assembly for per target if not many.

Sometimes it is a simple case of wanting the correct instruction to be used for example a 32 bit store must be used for some operation to insure that and not hope the compiler gets it right then use asm.

old_timer
  • 69,149
  • 8
  • 89
  • 168
0

There is no C equivalent for "return from exception". The C compiler can't translate everything that assembly can do. For instance, if you write an operating system you will need a special return function in the interrupt service routine that goes back to where the interrupt was initiated and the C compiler can't translate such a functionality, it can only be expressed in assembly.

See also Is assembly strictly required to make the "lowest" part of an operating system?

Niklas Rosencrantz
  • 25,640
  • 75
  • 229
  • 424
  • 3
    Some C compilers have proprietary extensions to support functionality like “return from exception.” – fuz Jul 18 '17 at 09:04
  • @fuz yes and no. One of the examples is gcc + arm CMSIS - and coder does not have to touch assembler even if he writes a RTOS. But it is only because many of the functions have been already written by the ARM as the inline assembly. For example `__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI(uint32_t value) { __ASM volatile ("MSR basepri, %0" : : "r" (value) : "memory"); }`. But even if you can write it in C, you still need to have a deep knowledge of the underlying hardware – 0___________ Jul 18 '17 at 09:11
0

Context switching is critical and need to be really really fast which should not be written in high level language.

S Dao
  • 555
  • 4
  • 7
  • 4
    That's not really the reason why. Modern compilers can generate code that is just as fast as handwritten assembly. – fuz Jul 18 '17 at 09:04
  • 2
    @fuz and some of the times, better than _handwritten_ assembly. – Sourav Ghosh Jul 18 '17 at 09:09
  • 1
    Not all instructions @fuz. "just as fast as handwritten assembly" sometime it's just a lie. BTW it's just because of history. – S Dao Jul 18 '17 at 09:43
  • Rewriting context switching in assembly language is an *optimization*, and although it might be an important one, it is *not* an answer to this question, which asks if there are kernel actions that *cannot* be written in C. If you wanted to make this an answer, you would need to talk about the implementation difficulties. (On this issue of modern compilers generating better code, it is safe to say that a modern optimizing compiler can generate code that is as fast as naively written assembly, but optimizers still are nowhere near as good as expert assembly programmers. Just a *lot* faster!) – Cody Gray - on strike Jul 18 '17 at 11:54
  • @sdao maybe today, but you cannot foresee new CPU features/instructions. C code can simply be re-compiled when a compiler features a new CPU, while assembler code must be rewritten – Tommylee2k Jul 18 '17 at 13:46
  • @CodyGray: **which asks if there are kernel actions that cannot be written in C** really? It's WHY question not WHAT/WHICH. – S Dao Jul 18 '17 at 15:53
  • Right, and the "why" is not because it's too slow, but because you cannot address individual registers in C. – Cody Gray - on strike Jul 18 '17 at 19:41