If a programme written in C needs system calls for execution, how can the operating system be written in C?
Posted by ADG_98@reddit | learnprogramming | View on Reddit | 47 comments
If I write a small command line programme in C, such as outputting the sum of two numbers, it need system calls for its execution. My question is how can the operating system also be written in C? How would the operating system make system calls?
no_regerts_bob@reddit
It's a good question. The C language allows you to directly access the hardware almost at the level of machine language, and it also allows you to embed actual machine language in your code.
The operation system and the standard C libraries use this to provide an abstract interface to your code. Your code just says "print this character", the libraries say "call the OS specific routine for printing characters", the OS says "hey VGA card/bios, print this character on the screen". All of this code can be written in the same language, ultimately everything is just machine code when it hits the CPU
ADG_98@reddit (OP)
Thank you for the reply. Is there a way for me to see or learn the code that can directly access the hardware. I am interested in writing a very small programme so that I can get better understanding.
arelath@reddit
Modern operating systems won't let you access the hardware directly. Only the kernel can access the hardware. Drivers are a way for third parties to run code in the kernel.
A good way to easily learn about how to interact directly with hardware is through embedded systems. Most embedded systems have no OS and you run your code directly on the hardware. Arduino boards are a popular and beginner friendly platform.
QFGTrialByFire@reddit
Hmm kind of - i guess for modern proprietary Win/Macos that might be the case as they enforce signed drivers so you need to get them to sign your driver. Even they i believe do let you sign test drivers yourself to run yourself.
However for modern Linux you can still write your own driver and access hardware yourself as it'll run in ring 0. No restrictions of signed drivers. The number of times you have to compile your own drivers to fix some random hw specific issue i don't think that will be going away soon. So if you want to mess around with hw you can just write your own driver in c compile to .ko file and load with insmod or modprobe do whatever you want as its your hardware.
marrsd@reddit
This implies a programme running in user space. I believe the parent is replying within this context.
QFGTrialByFire@reddit
Yup I totally get that and you are absolutely correct you cant run just a standard command line program in ring 0. Sorry if I came across as disagreeing. I just didn't want op to think that means you need to buy an Arduino or something - for some its not as cheap as for others and they already seem to have a pc. So they can write some driver code to learn hw control already it just means they need to learn how to compile the driver. Back before esp32s and Arduinos existed, microcontrollers were way more expensive to buy. A lot of people learned to do hw control on the soundblaster or use the lpt or rs232 ports. So if you don't have an Arduino or cant afford it you can still just use your pc to learn hw control. Also there are so many great chips you can find in people throwing away old computers - i'd encourage anyone to repurpose those for learning instead of landfill.
oh and happy cake day :)
marrsd@reddit
Thank you, I hadn't even realised. Apparently I only joined 10 years ago, which seems ridiculously late to the party. I was definitely lurking long before then :p
Particular-Cow6247@reddit
not even some linux distro?
QFGTrialByFire@reddit
I guess there are different levels as the poster above said. If you just want to control some hardware on you pc you'd likely still need the os to execute your program. That doesn't mean you don't control the hw it just means the os starts your program and allocates resources (memory, maps pages, and arranges for the CPU’s instruction pointer to fetch your program from memory, etc) for it to do that.
eg if you want to manipulate some registers you can but the OS will still load your compiled program - that doesn't mean you aren't directly controlling the hardware registers.
#include
#include
int main(void) {
unsigned long result;
asm volatile (
"mov $5, %%rax\n\t"
"mov $7, %%rbx\n\t"
"add %%rbx, %%rax\n\t"
"mov %%rax, %0\n\t"
: "=r" (result)
:
: "rax", "rbx"
);
printf("5 + 7 = %lu\n", result);
return 0;
}
But if you reallly want to control the hardware directly with no OS help at all .. you need to control the cpu's entry point on boot. Manage all the hw needed for your program. That means writing a minimal bios/bootloader, flashing that onto the uefi/bios rom chip. Have that bios program load your compiled program from disk and put it in ram. Have your bios program jump to that address of your compiled code in memory so the CPU fetches the first instruction from that location, execute it etc. You can see why all that boiler plate is then just given to the OS to do instead. You are basically starting to write an os at that point. I do think its useful for programmers to understand this tho even if they don't use it directly in the end. Now .. if you are an embedded systems engineer this kind of minimal os setup is what you do and you really do need to understand it.
If you want a great example of how this works, Ben Eater has a fantastic set of videos on it https://www.youtube.com/playlist?list=PLowKtXNTBypGqImE405J2565dvjafglHU. He goes all the way from simple transistors, to clocks, to flip flops, registers and builds a whole basic 8bit computer with custom opcode instructions and some assembly language to run some simple programs on it.
ADG_98@reddit (OP)
Thank you for the reply.
elves_haters_223@reddit
You can in fact embed machine code in c as well. I literally saw my college professor did a code demo in which he declared a char array and initialize to bytes of hex decimals like "\0x87\0x63....." And then cast that char array to a function pointer before invoking it.
I swear to God, c is pretty much just assembly but more human readable
no_regerts_bob@reddit
Pretty much, or at least that's how it started. It was a nice way to write portable but still almost machine level code.
cormack_gv@reddit
C allows access to machine language via the "asm" pseudo-function. System calls are typically implemented by special machine language instructions.
These "asm" statements are CPU and operationg-system dependent, so are typically isolated in a very small number of library routines that are implemented differently for different systems.
sububi71@reddit
Excellent explanation!
Old_Sky5170@reddit
Okay so response to your edit: It really depends on the kind of hardware you want to talk to. Usually you have a protocol (or contract of messages) that both the hardware and your „computer“ agree on. Common protocols have physical chips that are really good for that connection type and often at both sides of the connection.
A graphics card, harddrive, usb mouse etc. have their own brain (cpu) and they agree on different protocols (useful in their application) and all have special chips on the mainboard such that the cpu is not directly sending or receiving data with different protocols all the time. If you want to add a new device like an arduino usb is usually a good starting point. The arduino has a seperate chip to handle the transmission and make it usable for its cpu as well.
So one way is to give the arduino c code to for example turn on a led when it receives a certain message. You could then use some syscall or library to send this message via usb to the arduino.
If you are more interested in the protocols I would suggest passing binary data between treads and implement some protocol like cobs for message separation. If you have specific hardware you want to run then I would suggest to make a new post with the details of the hardware.
The explainations are not 100% correct to make it easier to understand
ADG_98@reddit (OP)
Thank you for the reply.
taker223@reddit
Short answer: every C program is compiled in machine code
elves_haters_223@reddit
I mean everything is compiled down to assembly then to machine code, not sure what the issue is.
dorox1@reddit
There was a great video posted just last week on Computerphile about "bootstrapping". They talk about how "the most recent version of C is written in C". The same applies to operating systems and the video is only 20m long. You might find it interesting.
Osaka_S@reddit
The very thing I thought of when I saw this question. I was surprised when I first watched it to hear him say C was a “high level language”.
2h_company@reddit
I was just gonna find it for this thread. It was a pretty good explanation.
ADG_98@reddit (OP)
Thank you for the reply. I will check it out.
chcampb@reddit
Ooh I can answer this
It makes more sense when you consider how processors work at the lowest levels. It's really just read the instruction, execute the instruction, over and over again. And the instruction is just, read or write memory or registers, either from memory or from an immediate (literal) value, or to or from something like a floating point or SIMD coprocessor.
Another thing the processor does is interrupts - which are basically, your program goes from the current instruction to the next instruction, but gets abducted and the program counter (pointer) gets sent somewhere else to execute some quick logic to service something requiring low latency (like mouse or keyboard or something).
When you realize that, then it becomes less a question of how C can access system stuff and more about "what peripherals can I access to do the thing I want." Peripherals are typically memory mapped, meaning, they exist in memory at a certain location, where RAM may appear somewhere else. One important peripheral is an MPU - Memory Protection Unit.
So an OS will typically run in privileged mode, where it has access to everything, but then shut down access to everywhere except the memory location granted to a process. To do that you would, in a lot of processors, set a value to a register that you do have access to, and then trigger a service interrupt. The processor sees that, jumps to the interrupt, sets privilege, and then does the thing you want it to do. It's not generally going to give access to the program itself, but what it will do is ask the processor to do something that you can't normally do.
ADG_98@reddit (OP)
Thank you for the reply.
POGtastic@reddit
The syscalls themselves are written in C, too! Here's
write
, for example.The process of context-switching from userspace to kernelspace is the part that's hardware-specific and requires some platform-specific assembly.
ADG_98@reddit (OP)
Thank you for the reply.
Mission-Landscape-17@reddit
End user programs need to use system calls because the os prevents you from accessing hardware directly. The os itself does access hardware directly. If you want to play with direct hardware access try playing with an Arduino. Arduino code is written in c and manipulates the underlying hardware directly.
ADG_98@reddit (OP)
Thank you for the reply.
captainAwesomePants@reddit
The other answers are good, so I'll just give a practical example. When you call printf(), printf() will figure out which string should be printed, and then it will make the "write" system call, asking the kernel to put that string onto the stdout file. Then the kernel has it, and it will copy those bytes to that file as requested.
In the kernel, if you want to print some text, you can't use printf(). The kernel doesn't have its own standard out, it wouldn't mean anything. And you can't make system calls anyway. Instead, you'd call the "printk()" function, which figures out which string should be printed, then copies the new message to a ring buffer that users can read later.
ADG_98@reddit (OP)
Thank you for the reply.
teraflop@reddit
A system call is basically just a fancy kind of function call. The special thing about a system call is that it allows user code (running with low privileges) to call kernel code (running with high privileges). Within the kernel itself, plain old function calls are used.
In terms of what those function calls within the kernel actually do: sometimes they just manipulate data, like any other function you might write yourself. For instance, the "list of running processes" is a kernel data structure, so when you start a new process running, you're just calling kernel code that adds a new entry to that list.
Similarly, when you use a syscall to "print" text from your program, what you're really doing is writing characters to a queue (a.k.a. a pipe or FIFO). Some other part of the system (e.g. a terminal emulator) is going to read those characters and figure out how to display them on the screen. The queue itself belongs to the kernel, so programs use syscalls to ask the kernel to read and write it.
On the other hand, some of the kernel code has to manipulate hardware. It usually does this by accessing special memory addresses (memory-mapped I/O) which read or write the corresponding registers in a hardware device. The kernel's higher privilege level allows it to do this directly.
ADG_98@reddit (OP)
Thank you for the reply.
Rainbows4Blood@reddit
C itself is not dependent on syscalls.
The purpose of syscalls is simply to access OS functions, and then the OS will talk to the hardware to do something like make text appear on your command line.
The OS on the other hand will not use syscalls. It talks to the hardware by, for example, writing to specific memory addresses that control the hardware. This is quite complicated, the OS will usually have multiple implementations (drivers) for different hardware, etc.
Syscalls exist for two reasons. 1) It makes it easier to write software because the OS takes the complex parts for you. 2) The OS won't allow you to access the hardware directly, because that would be a massive security risk. Only the OS may access hardware directly.
ADG_98@reddit (OP)
Thank you for the reply.
da_Aresinger@reddit
This is basically like asking "If you need farmers to get food, how can farmers eat?"
"Operating System" is just a job, that a group of programmes on your PC are performing.
And just like it doesn't matter if the farmers are white, black or asian, it's irrelevant if the programmes are written in C, Java or Python. At the end of the day it's all assembly(/machine code/micro code)
maybe I'm taking this a bit far... anyway:
Syscalls are just services that specific programmes provide. The OS itself also uses the same syscalls.
dnult@reddit
The computer doesn't "run C". It runs a compiled version of the C program that is actually in machine code - just like the system code. C (and other languages) are simply a way for human beings to write what eventually becomes machine code after compilation.
demeneghi@reddit
This is the answer!!
SeriousDabbler@reddit
There are so many layers of abstractions. The OS runs on the same hardware but at a different privilege level and often has access to privileged instructions and more memory and is in charge of context switching which often is hardware assisted but involves preserving the state of a software thread, changing the accessible memory locations, and reinstating another software thread
balrob@reddit
Firstly when you say “operating system”, you are addressing very large bodies of software that include everything from user level programs not much different from yours, down to the kernel, and everything in between - drivers, services, file systems etc. the rules change at different layers. Your simple program calls printf (or similar) which is library code - it’s in a lib or dll and is linked statically or dynamically into your program. The writer of kernel
Fridux@reddit
The operating system doesn't make system calls, it just takes them and talks to hardware. Making a system call involves issuing a specific low level instruction telling the hardware to interrupt execution and run whatever code the operating system kernel configured to run under those conditions. As part of the interrupt configuration, the operating system may also declare that the code that the CPU is jumping to must be executed with elevated hardware privileges so that it can access hardware facilities that a normal process cannot, which it then uses to store the context of the calling process, check whether that process has the required privileges and, if so, execute the requested operation, before restoring the context of the calling process and issuing yet another low level instruction to return execution back to the process, optionally dropping the elevated privileges, and with the result of the operation usually stored in a hardware register for the process to evaluate.
iOSCaleb@reddit
Once the OS and program have been compiled, it doesn’t matter what language they were written in.
If they’d both been written in assembly code, the user program would still need system calls to access system services. The system calls aren’t there to translate from C to OS, they’re there to define the system services that the IS provides to user code.
vegan_antitheist@reddit
C code can be compiled so it runs on operating systems that are not written in C, such as RedoxOS. There's relibc, which is written in Rust. So you can compile code written in C to run on RedoxOS.
Note that at runtime there is no C code and no Rust code. It's all machine code. It's all compiled to code that the machine (the computer) can run directly. That means it's exactly the instructions the CPU understands.
Fluffy_Chipmunk9424@reddit
it's not c asking computer.its machine code instructions running in user space asking os to do something which it can't coz of limited accesibility.your code is in binary(machine code) after compilation not c
DTux5249@reddit
A program in C doesn't need system calls. C programmers that aren't building an OS appreciate system calls. There's a difference.
You don't have to use any of the major C libraries. Such methods are arcane horrors beyond my comprehension, but it is possible.
SwordsAndElectrons@reddit
When you make system calls, you are calling a function that is part of the API of the OS. What makes you think the implementation of that function can't also be written in C?
Those system calls are not part of how C works. They are how writing a program targeting that OS works. If another part of the OS needs to call that function then it does. It's just like how your program can call another function that is defined within it.
FloydATC@reddit
The very first C compiler was written in some other language, as was the operating system of that computer. When that compiler was good enough, it could be used to write any program, including compilers and operating systems.
What language was used to create an operating system has very little to do with what languages can invoke system calls of that operating system.
And finally, you do not typically invoke the operating system for things like adding numbers; such things are typically handled by the CPU itself, meaning the C compiler just has to generate whatever machine code the CPU needs. A good programmer tries to use system calls only when strictly needed.
lfdfq@reddit
System calls are to let your programs ask the OS to do something for you.
The OS doesn't need to ask itself to do something, it can just do it.