Running a program in kernel mode forbids using standard C library because the only thing your program linked to is kernel itself. So I'm allowed to use functions defined in kernel. But kernel itself is a program written in C and compiled for some particular architecture. And it shouldn't use C standard library, but it also shouldn't use any drivers since drivers are loadable modules. So my question is what actual C functions are used when writing a kernel? How can you interact with hardware not through kernel? Don't say me to look at sources it's too next level for me, TY.
closed as too broad by Rui F Ribeiro, steve, Jeff Schaller♦, Scott, lcd047 Jun 27 '16 at 4:45
Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.
The Unix kernel has traditionally included some assembly language code. I haven’t looked at its source code recently, but I suspect that that’s still true.
See How does a driver actually communicate with a hardware device? for an overview of that topic. The answers to that question discuss two kinds of computer architecture. On a system that uses port-mapped I/O (PMIO), the kernel must be written partly in assembly language — although you may be able to get by with a couple very short routines. On a system that uses memory-mapped I/O (MMIO), even device drivers can be written entirely in C. All they need to do is declare a pointer, set it equal to the virtual address of the device, and then use it to manipulate the device as if it were accessing memory.
Not all drivers are loadable modules, being loadable is simply an option but some crucial drivers are not dynamically loaded, they are part of the kernel.
The kernel reproduces a whole bunch of the functionality provided by libc statically, within itself.
Just like in user-mode C programming, a function can be defined in one compilation unit and another unit can simply reference it (usually via a header file), the compiler will make it an undefined reference, and the linker will link it with the compilation unit that actually provides the symbol.