So when we compile a simple source code, say with just a printf() function, and the compilation produces the executable machine code, will each instruction in this machine code be directly be executed from the memory (once the code is loaded into the memory by OS) or will each each command in the machine code still need to go through the OS(kernel) to be executed?
Essentially, only system calls go to the kernel. Anything to do with I/O or memory allocation/deallocation typically eventually results in a system call. Some instructiosn can only be executed in kernel mode and will cause the CPU to trigger an exception. Exceptions cause a switch to kernel mode and a jump to kernel code.
The kernel does not process every instruction in a program. It just does the system calls and switches between running programs to share the CPU.
Doing memory allocation in user-mode (without the kernel) is not possible, if you access memory you don't have permission to access, the MMU, previously programmed by the kernel, notices and causes a CPU-level "segmentation fault" exception, which triggers the kernel, and the kernel kills the program.
Doing I/O in user-mode (without the kernel) is not possible, if you access I/O ports or registers for devices, or addresses connected to devices (one or both needed to perform any I/O), these trigger an exception in the same way.
Would a executable need a OS kernel to run?
Depends on the type of executable.
Kernels, in addition to mediating shared access to RAM and hardware, also perform a loader function.
Many "executable formats", like ELF or PE, have metadata in the executable file in addition to the code, and its the loader's job to process that. Read the gory details about Microsoft's PE format for more information.
These executables also reference libraries (Windows
.dll or Linux shared object
.so files) - their code has to be included.
If your compiler produces a file that's meant to be processed by an operating system loader, and that loader is not there, it won't work.
- Can you include code that does the job of the loader?
Sure. You need to convince the OS to somehow run your raw code without processing any metadata. If your code calls kernel APIs, it still won't work.
- What if it doesn't call kernel APIs?
If you load this executable somehow from an operating system somehow (i.e. if it allows raw code to be loaded and executed), it will still be in user mode. If your code accesses things that are prohibited in user mode, as opposed to kernel mode, such as unallocated memory or I/O device addresses/registers, it will crash with privilege or segment violations (again, exceptions go to kernel mode and are handled there) and still won't work.
- What if you run it from kernel mode.
Then it will work.