Re: Why ! C++
On Mar 5, 12:03 pm, SasQ <s...@go2.pl> wrote:
So how it's been done? I'm very curious about that,
because the plain old C doesn't need any runtime
support AFAIK.
Of course C needs run-time support. What run-time support is needed
depends on the compiler. Not every expression, declaration or
statement is necesarily turned into pure inline machine code.
On some RISC-like processors, for instance, some math operations, even
simple integer ones like divisions, may necessitate the use of a
library routine. This explains the various __mul* and __div* type
functions in the GNU compilers's ``libgcc'' library. If you're using
GCC to write a kernel, then you still have to supply that library.
How about structure initialization and assignment?
Code like
some_struct x = { 0 };
/* ... */
y = x;
may actually translate into machine code which calls memset and
memcpy. If you don't supply these, the thing won't link due to
unresolved references.
C++ construction and destruction has its API also. One possibility is
for the comiler to generate a special hidden construction and
destruction hook functions. Each object file with C++ objects in it
has such functions.
The embedded kernel's startup code would have to have a routine which
would iterates over these functions and calls them.
Now how do you get a list of these functions? One possible way is to
make use of a linker feature known as named sections (also known as
segments). If you've done assembly language programming, you might
have run into conventional sections like .text or .data.
Anyway, for each constructor hook function, a variable holding a
pointer to that function (by way of a symbolic reference that will be
resolved at link time) is also emitted, and that variable is placed
into a section. When the objects are linked, the linker will merge all
of the objects that belong to the same section name into one
contiguous segment of memory in the target object. The routine then
simply has to iterate from some symbolic address marking the section
start to another symbol which resolves to the section end. It knows
that the section contains nothing but pointers to the constructor
functions which are all equally wide, and so essentially it is working
with an array of pointers set up by the linker. And that is how you
can complete the run-time support for C++ global construction and
destruction. The compiler does one part, a linker script defines the
sections to do the second part, and some loop does the rest.
Exceptions? Similar concept. There will be some exception handling ABI
expected by the generated code, which the system has to complete. That
ABI will have some function for unwinding the stack frame by frame,
querying each frame for useful information such as the entry point for
clean-up cod for that frame, etc. The ABI has to map to the
concurrency model also. Do you allow exceptions within interrupt
service routines? If so, the unwinder has to know that it's in an
interrupt stack, and how to recognize that it's hit the top of it,
etc. Moreover, the interrupt may have gone off while the interrupted
task context was processing an exception already, so the two can't get
mixed up, etc.