I suppose, this thread wasn't much about selecting a language.
Use Rust, Luke.
I suppose, this thread wasn't much about selecting a language.
I avoided malloc() calls like the plague when implementing PDCLib stdio, and to my knowledge wrote one of the very few printf() implementations that can do without dynamic memory.gerryg400 wrote:You need to supply a malloc replacement that works in your kernel if you want to use, for example, strdup(). Lot's of libc requires malloc, including some parts of stdio.
Yeah I have. It's not open source, but I might eventually write a wiki entry about it.MollenOS wrote:Have you implemented support for the VC++ abi? Do you have any repository I could check (and mind sharing) ? I had totally given up because of the lack of documentationdseller wrote:You should also absolutely be aware of the C++ runtime which you are required to implement if you want to take advantage of all features. If your OS is linux-like, you can probably port libsupc++. This is if you are lucky enough to have chosen G++ as a compiler. Myself, I decided to a) write a completely independent OS, and b) use the Visual C++ compiler. Almost zero documentation on that, but it works now.
Basically, you need the RTTI (Runtime Type Information) to do things like dynamic_cast<T>(), and typeinfo() stuff. Also, if you want to use exceptions, you need to implement a runtime for that as well.
If you're not into that, and will never use polymorphic classes with virtual methods which you want to cast to their derived classes, you can disable RTTI. (-fno-rtti in G++, /GR-). This does allow you to perform basic polymorphism.
EDIT: Maybe this provides a little insight http://www.codingunit.com/cplusplus-tut ... -type_info
A lot of what you just said is why I'm now leaning away from attempting to implement STL logic in the kernel itself. As I said before, at the very least, it will create a conundrum (at least for clarity's sake) where different parts of the kernel are operating at different levels of abstraction, basal layers having to set up C and C++ underpinnings, with other levels making use of them. I've decided it'll probably be much easier for me to do one of the following:gerryg400 wrote:Actually no. If you have a Posixy libc and a Posixy kernel then you will have no trouble supporting gcc's libstdc++ in userspace. There is almost no OS support required other than the standard Posix interfaces like open(), read(), write() etc. and a few other bits and pieces like atexit(). The so-called advanced features like rtti and exceptions work fine with almost no help from the OS other than that required by libc.
The reason we say that it's difficult to use the entire of libstdc++ in your kernel is that you need a libc that works in your kernel. This is difficult (i.e. lots of time and knowledge required) because a lot of required libc pieces which are designed to be used in userspace are more difficult to use in kernel space. For example, any libc function that might make a system call needs to be rewritten in such a way that it works 'within the system' and not outside it. Furthermore, the C++ runtime will, depending on which is chosen, need kernel-side replacements for concepts like mutexes, condvars, exit(), atexit(), stdin, stdout, stderr, environment variables, locale, new, delete and mmap. In other words it is much quicker and easier to write your own string class than to use the libstdc++ one.
That's fair. The main attraction for me to using C++ is the class/object model and the ability to segregate and demarcate code via classes and methods; for what it's worth, I'm much more versed in C, so my decision to use C++ is going against the grain not in an insignificant way.Solar wrote:So... my bottom-line take:
By all means, if it's your language of choice, do use C++ (rather, a subset of it) in kernel space. It brings a lot of syntactic sugar to the table that is nice to have, and it wouldn't be that much of an effort to write up whatever container class you need, mimicking standard library behaviour as far as required.
But don't get it into your head that you'd have to create a "complete" C++ environment for the kernel (with RTTI, exceptions, standard library, ...) because it would be a wasted effort.
For the reasons above, the interface to userspace should be extern "C" anyway, and in userspace, you can use whatever C++ compiler / library you want to.
MollenOS wrote:Have you implemented support for the VC++ abi? Do you have any repository I could check (and mind sharing) ? I had totally given up because of the lack of documentation
You're preaching to the choir with that one. I as a rule try to avoid things that muck with exceptions even in general-purpose projects. My life is much easier without them.n0x wrote:Exceptions (which require RTTI themselves). Why would you ever need them at all (IMHO)?
On the RTTI front, how do I avoid using it (and use C++ solely for linguistic rather than runtime features)? Is there any special setup to force a compiler to emit "dumb" non-RTTI code or code designed for a target without a RTTI implementation?n0x wrote:[/list]
- RTTI: typeid() and dynamic_cast(). The only case when you actually need dynamic_cast() is to down-cast from the virtual base. That is if you actually have some diamond inheritance, which can actually happen in iostreams (or equivalent) classes, but I don't think there is any down-casting there. Classes with virtual methods but without virtual base DO NOT require any library support, except maybe pure virtual function stub.
- Global initializers which you will have to call if you have any non-trivially constructable global variables (which you probably will). Also beware of the global arrays for which C++ compilers like to generate initializers instead of initializing in compile time. This can happen to a global array whose initializer values seem to be unknown to compiler at compile this. It happened to my IDT!
Code: Select all
typedef void(*func)();
__attribute__((section(".ctors_begin"))) func ctors_begin = nullptr;
__attribute__((section(".ctors_end"))) func ctors_end = nullptr;
__attribute__((section(".dtors_begin"))) func dtors_begin = nullptr;
__attribute__((section(".dtors_end"))) func dtors_end = nullptr;
void main()
{
for (func *ctor = &ctors_begin + 1; ctor < &ctors_end; ++ctor)
(*ctor)();
/* Your C++ kernel code */
/* This probably won't make much difference since it's done before your OS shutdown */
for (func *dtor = &dtors_begin + 1; dtor < &dtors_end; ++dtor)
(*dtor)();
}
Code: Select all
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.ctors_begin)
*(.ctors)
*(.ctors_end)
*(.dtors_begin)
*(.dtors)
*(.dtors_end)
*(.rodata)
}
The same issues apply. They apply to the libraries of any high-level language being using on OS dev. Changing the language just transposes it into a different chord.
I was totally not aware of this ABI issue... thx for this mind opener... I was living in a pinky world of "avoid RTTI and most libs and all will be OK" and somehow some (more) grey leaked in now... kernel interface to be "extern C" ed... wow! I had seen projects that put some mighty effort to wrap ol' C interfaces into smoothy C++ cream... and now this...Solar wrote: However, there is one thing that hadn't popped up in this thread yet: ABI.
You know, neither the in-memory layout of C++ objects nor the specifics of C++ name mangling are specified by the language. Every compiler implementor does his own thing here. The Itanium C++ ABI went a long way toward an agreement between implementors, but the name mangling is still all over the place.
So if you intent to export a C++ API from kernel space, you are basically doing a lock-in of the whole userspace to a specific compiler version.