views:

804

answers:

6

Hi, I always thought that functions like printf() are in the last step defined using inline assembly. That deep into stdio.h is burried some asm code that actually tells CPU what to do. Something like in dos, first mov bagining of the string to some memory location or register and than call some int. But since x64 version of Visual Studio doesent support inline assembler at all, it made me think that there are really no assembler-defined functions in C/C++. So, please, how is for example printf() defined in C/C++ without using assembler code? What actually executes the right software interrupt? Thanks.

A: 

The compiler generates the assembly from the C/C++ source code.

Terry Mahaffey
+2  A: 

The standard library functions are implemented on an underlying platform library (e.g. UNIX API) and/or by direct system calls (that are still C functions). The system calls are (on platforms that I know of) internally implemented by a call to a function with inline asm that puts a system call number and parameters in CPU registers and triggers an interrupt that the kernel then processes.

There are also other ways of communicating with hardware besides syscalls, but these are usually unavailable or rather limited when running under a modern operating system, or at least enabling them requires some syscalls. A device may be memory mapped, so that writes to certain memory addresses (via regular pointers) control the device. I/O ports are also often used and depending the architecture these are accessed by special CPU opcodes or they, too, may be memory mapped to specific addresses.

Tronic
But these calls are not deep within stdio.h
anon
Added info about direct hardware access.
Tronic
All correct but just FYI amd for others posting in this thread most modern OS and architectures now use special opcodes to actually execute systemcalls(e.g sysenter and sysexit on x86), rather than using software interrupts, to improve performance.
+1  A: 

Well, all C++ statements except the semicolon and comments end up becoming machine code that tells CPU what to do. You can write your own printf function without resorting to assembly. The only operations that must be written in assembly are input and output from ports, and things that enable and disable interrupts.

However, assembly is still used in system level programming for performance reasons. Even though inline assembly is not supported, there is nothing that prevents you from writing a separate module in assembly and linking it to your application.

Vlad
+1  A: 

In general, library function are precompiled and distribute ad object. Inline assembler is used only in particular situation for performance reasons, but it's the exception, not the rule. Actually, printf doesn't seems to me a good candidate to be inline-assembled. Insetad, functions like memcpy, or memcmp. Very low-level functions may be compiled by a native assembler (masm? gnu asm?), and distribute as object in a library.

Giuseppe Guerrini
+3  A: 

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.

Macmade
printf() works on systems that don't have a kernel, or a ring-based architecture
anon
+22  A: 

You're of course right that the rubber has to meet the road at some point. But there's a lot of layers to go through before you can find that place! It sounds like you have some preconceptions based on the DOS days, and that's not too relevant anymore.

There've been some good general points made here, but no one has linked to the precise devils in the details of the source. So in order to make you sufficiently sorry that you asked :) I did a thorough trace of the printf story for GNU's libc and Linux..trying not to hand-wave about any of the steps. In the process I brought some of my own knowledge up to date:

http://hostilefork.com/2010/03/14/where-the-printf-rubber-meets-the-road/

WARNING: It's not for the easily bored!

Hostile Fork
Post it as an answer please, don't just link to an external source. (Especially not a blog, since blogs notoriously gets overhauled and lose content.)
kb
O ye of little faith!! (Or rather, seems you merely have more faith in stackoverflow.com than hostilefork.com, so I guess Joel and Jeff are just cooler than me. :P) I'd say that links power the web - if I ever updated the article to improve it, following your suggestion I'd then have to improve it in two places. I empathize with your concern on general principle, but since there's no robots exclusion on hostilefork.com, Google (already cached) and archive.org (in a few months) will be able to bridge past any webmastering incompetence on my part...
Hostile Fork
I would argue we do have more faith in SO than a blog because it, arguably, has greater at stake. More importantly, though, not placing it here makes it non-searchable through these mechanisms. If you want this to be future editable, make it a community wiki. Perhaps you should link your blog here instead, so as to maintain consistency? Just a thought.
Nazadus