Use of C++ as a development language

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Roman
Member
Member
Posts: 568
Joined: Thu Mar 27, 2014 3:57 am
Location: Moscow, Russia
Contact:

Re: Use of C++ as a development language

Post by Roman »

Satoshi wrote:Use D as a development language.

Here is example https://github.com/Rikarin/Trinix
I suppose, this thread wasn't much about selecting a language.

Use Rust, Luke.
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
- Alan Kay
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Use of C++ as a development language

Post by Solar »

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.
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.

freopen() can be called with a NULL filename, and is expected to re-open the file... so you need to store the filename in the FILE struct somehow. You could either declare a large-ish static array (artificially limiting filename length), or use malloc().

(I haven't actually used VLA's, ever, but since I expect PDCLib to be fully downwards compatible, they are out of the picture anyway.)

But setvbuf() is specified to allocate a buffer if none was given by the user. ;-)

You see how easy it would be to make PDCLib work without any malloc() -- you don't really need freopen() or setvbuf() in a kernel, so just leave them out, and you can do without malloc(). (However, you will need malloc() in the kernel anyway, so the snake is biting its tail here.)

It's the same with the C++ library: You can make (large parts of) it work in kernel space, but since very few (any?) C++ library implementations are written with kernel space support in mind, they don't make it easy (because, why should they?).

----

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.

Plus, user-space languages basically expect a C API. You would have to do a lot of wrapping to get Perl, Python et al. to work on your C++-API kernel -- and you can forget about any upstream support for this.

----

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.
Every good solution is obvious once you've found it.
dseller
Member
Member
Posts: 84
Joined: Thu Jul 03, 2014 5:18 am
Location: The Netherlands
Contact:

Re: Use of C++ as a development language

Post by dseller »

MollenOS wrote:
dseller 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
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
Yeah I have. It's not open source, but I might eventually write a wiki entry about it.
physecfed
Member
Member
Posts: 45
Joined: Sun Feb 28, 2016 5:33 pm
Location: Merced, California
Contact:

Re: Use of C++ as a development language

Post by physecfed »

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.
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:
  • Brew "metal-friendly" implementation-specific versions of classes such as string or vector analogues as I need them, or
  • Simply stick with C++ for its syntax, and otherwise just get comfortable with the same low-level mechanics I'm used to from C.
The second might be easier for the time being, and I can reevaluate the first as things begin to move in a definite direction. I like the idea of being able to work in C++ for a kernel at a level similar to userspace programming, but then again, I want to fill my time with kernel development and not run-time environment for future kernel development. Building the car is hard enough; I would rather not attempt to produce the bolts by hand.
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.
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.

As you said, it might be worthwhile to draw up container classes as I need them, but I'm not opposed to living without them. I am, after all, purely using the language for its syntactic sugar that you mention.
n0x
Posts: 5
Joined: Wed Jun 03, 2015 10:49 pm

Re: Use of C++ as a development language

Post by n0x »

C++ is very much usable for kernel development. You can find a lot of C++-based kernel on OSDev. I am currently also using C++ to create a kernel.
A C++ library, as was already mentioned, is another matter. It is actually the same as with libc, you just won't have it until you implement it yourself. You can also NOT implement the standard library and try to come up with something of your own making (we are all wheel reinventors here after all :) ) unless of course you'll want to port something to your OS that depends on it (which is just about everything).

However most of the C++ language features work without any library support whatsoever, except:
  • 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.
  • Exceptions (which require RTTI themselves). Why would you ever need them at all (IMHO)?
  • 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!
n0x
Posts: 5
Joined: Wed Jun 03, 2015 10:49 pm

Re: Use of C++ as a development language

Post by n0x »

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
  • The first place you should look is of course "VC\crt\src" in your Visual Studio folder (better be 2015). It contains C and C++ Microsoft's library implementation (including RTTI, exceptions, etc...), admittedly some files are missing (on purpose?).
  • The second is LLVM's Clang (surprisingly) source code which seems to contain modules for generating ABI of different compilers including MSVC. I personally saw an RTTI implementation there which is better documented than whatever lives in "VC\crt\src".
  • Also you can find on the web this kind of articles written by some Win32 hackers which want to distinguish library and compiler generated code from actual application code :).
You can also find several projects attempting to replace the bloated msvcrt with a smaller ones like this. They may shed some light on what support does MSVC requires from the library if that is what you are after.
physecfed
Member
Member
Posts: 45
Joined: Sun Feb 28, 2016 5:33 pm
Location: Merced, California
Contact:

Re: Use of C++ as a development language

Post by physecfed »

n0x wrote:Exceptions (which require RTTI themselves). Why would you ever need them at all (IMHO)?
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:
  • 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!
[/list]
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?

In regards to the second point (I've begun looking at that link, but it's fairly dense/terse in its writing), do the global constructors require memory allocation support in the kernel? (That is, do I need to have memory allocation tried and true before I can start writing components in C++?)
User avatar
Rusky
Member
Member
Posts: 792
Joined: Wed Jan 06, 2010 7:07 pm

Re: Use of C++ as a development language

Post by Rusky »

GCC and Clang have -fno-rtti, MSVC has /GR-.

Global constructors don't require memory allocation, only that you manually call them (normally part of _start's job in libc). You can do it the way the compiler expects (for GCC there's a section in the output binary with an array of function pointers), or you can just call them yourself with placement new.
n0x
Posts: 5
Joined: Wed Jun 03, 2015 10:49 pm

Re: Use of C++ as a development language

Post by n0x »

There is a fairly simple way you can call global initializers using your linker script but without dealing with compiler's internal object files. It worked for me on Clang and should probably work with GCC, however I didn't test it. MSVC has a little bit different section names but the approach is fairly similar (see the OSDev article).

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)();
}
Linker script part:

Code: Select all

	.rodata BLOCK(4K) : ALIGN(4K)
	{
		*(.ctors_begin)
		*(.ctors)
		*(.ctors_end)
		*(.dtors_begin)
		*(.dtors)
		*(.dtors_end)
		*(.rodata)
	}
I put all these sections into .rodata (seems logical) but you can put them anywhere you want as long as you preserve the order.
The main point of this approach is to mark the beginning and the end of compiler-generated arrays of initializers using variables that you can access from your code.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Use of C++ as a development language

Post by Schol-R-LEA »

Satoshi wrote:Use D as a development language.

Here is example https://github.com/Rikarin/Trinix
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.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
TverrBjelke
Posts: 23
Joined: Thu Apr 24, 2008 6:14 am

Re: Use of C++ as a development language

Post by TverrBjelke »

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.
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...
Post Reply