I always thought that functions like printf()
are, in the last step, defined using inline assembly. That deep in the bowels of stdio.h is buried some asm code that actually tells CPU what to do. For example, in dos, I remember it was implemented by first mov
ing the beginning of the string to some memory location or register and than calling an int
terupt.
However, since the x64 version of Visual Studio doesn't support inline assembler at all, it made me wonder how there could be no assembler-defined functions at all in C/C++. How does a library function like printf()
get implemented in C/C++ without using assembler code? What actually executes the right software interrupt? Thanks.
A function consist of two parts: Declaration: the function's name, return type, and parameters (if any) Definition: the body of the function (code to be executed)
A function has three parts, a set of inputs, a set of outputs, and a rule that relates the elements of the set of inputs to the elements of the set of outputs in such a way that each input is assigned exactly one output.
We can write assembly program code inside c language program. In such case, all the assembly code must be placed inside asm{} block.
It is an error if the number of arguments in a function definition, declaration, or call does not match the prototype. If the data type of an argument in a function call does not match the corresponding type in the function prototype, the compiler tries to perform conversions.
First, you have to understand the concept of rings.
A kernel runs in ring 0, meaning it has a full access to memory and opcodes.
A program runs usually in ring 3. It has a limited access to memory, and cannot use all the opcodes.
So when a software need more privileges (for opening a file, writing to a file, allocating memory, etc), it needs to asks the kernel.
This can be done in many ways. Software interrupts, SYSENTER, etc.
Let's take the example of software interrupts, with the printf() function:
1 - Your software calls printf().
2 - printf() processes your string, and args, and then needs to execute a kernel function, as writing to a file can't be done in ring 3.
3 - printf() generates a software interrupt, placing in a register the number of a kernel function (in that case, the write() function).
4 - The software execution is interrupted, and the instruction pointer moves to the kernel code. So we are now in ring 0, in a kernel function.
5 - The kernel process the request, writing to the file (stdout is a file descriptor).
6 - When done, the kernel returns to the software's code, using the iret instruction.
7 - The software's code continues.
So functions of the C standard library can be implemented in C. All it has to do is to know how to call the kernel when it need more privileges.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With