Hi, I'm an operating system developer. I've written a win32-compatible and
POSIX operating system, just for fun, but it can run many windows api programs.
My system is written in C, it is not readable and diffcult to manage. Now I am
looking for the new techniques to rewrite this os.
I've ever thought for an own compiler and linker, it is so complicated to
develop an advanced one. But DMD did it, the D language almost satisfied what I
need. Yes, you see, I am trying to use it to develop an operating system in D
language, and maybe it will be the first one written in D language.
While I was using C++ developing an os, the compiler can output the
platform-independent code. But DMD compiler can not do this, because it needs a
runtime library based on the present platform.
I have tried gdc, but I failed too. It prints the error below when I link:
ld: warning: cannot find entry symbol _mainCRTStartup; defaulting to 00401000
hello.o(.text+0x18):hello.d: undefined reference to `_Dmodule_ref'
hello.o(.text+0x23):hello.d: undefined reference to `_Dmodule_ref'
hello.o(.data+0x0):hello.d: undefined reference to `_D10ModuleInfo6__vtblZ'
hello.o(.data+0x30):hello.d: undefined reference to `_D6object12__ModuleInfoZ'
Now I am wondering how can I link a platform-independent executable file?
Do I need to rewrite the runtime library?
Or just I need to write a tiny runtime library like gc, moduleinit, object?
I hope you can help me solve these puzzles, thanks!

Hi, I'm an operating system developer. I've written a win32-compatible and
POSIX operating system, just for fun, but it can run many windows api programs.
My system is written in C, it is not readable and diffcult to manage. Now I am
looking for the new techniques to rewrite this os.
I've ever thought for an own compiler and linker, it is so complicated to
develop an advanced one. But DMD did it, the D language almost satisfied what I
need. Yes, you see, I am trying to use it to develop an operating system in D
language, and maybe it will be the first one written in D language.
While I was using C++ developing an os, the compiler can output the
platform-independent code. But DMD compiler can not do this, because it needs a
runtime library based on the present platform.
I have tried gdc, but I failed too. It prints the error below when I link:
ld: warning: cannot find entry symbol _mainCRTStartup; defaulting to 00401000
hello.o(.text+0x18):hello.d: undefined reference to `_Dmodule_ref'
hello.o(.text+0x23):hello.d: undefined reference to `_Dmodule_ref'
hello.o(.data+0x0):hello.d: undefined reference to `_D10ModuleInfo6__vtblZ'
hello.o(.data+0x30):hello.d: undefined reference to `_D6object12__ModuleInfoZ'
Now I am wondering how can I link a platform-independent executable file?
Do I need to rewrite the runtime library?
Or just I need to write a tiny runtime library like gc, moduleinit, object?
I hope you can help me solve these puzzles, thanks!

I'm sorry OS dev isn't really my thing, but I can maybe point you to
some stuff.
There used to be a fairly well organized kernel written in D called
Titan, but their site is down so that project is probably past its time.
But Titan wasn't the only D OS kernel project, here are some others:
http://www.geocities.com/one_mad_alien/dkernel.htmlhttp://www.dsource.org/projects/osianhttp://trac.brainsware.org/ocd/
(This is also not an exhaustive search by any means.)
Hopefully other D users will be able to give more specific pointers on
the topic, but until then I suggest just looking at what others have
done to bootstrap a D OS into reality (it's been done).

I'm sorry OS dev isn't really my thing, but I can maybe point you to
some stuff.
There used to be a fairly well organized kernel written in D called
Titan, but their site is down so that project is probably past its time.
But Titan wasn't the only D OS kernel project, here are some others:
http://www.geocities.com/one_mad_alien/dkernel.htmlhttp://www.dsource.org/projects/osianhttp://trac.brainsware.org/ocd/
(This is also not an exhaustive search by any means.)
Hopefully other D users will be able to give more specific pointers on
the topic, but until then I suggest just looking at what others have
done to bootstrap a D OS into reality (it's been done).

Yes, these links are useful. But these projects seem to stop for a long time.
Also, they used the old D compiler, not compatible with the present compiler.
I think I should have a look at the phobos runtime library, and write a new one.

Hi, I'm an operating system developer. I've written a win32-compatible and
POSIX operating system, just for fun, but it can run many windows api programs.
My system is written in C, it is not readable and diffcult to manage. Now I am
looking for the new techniques to rewrite this os.

I'm writing a toy "OS kernel" for fun (in D), so I might be able to help.

I've ever thought for an own compiler and linker, it is so complicated to
develop an advanced one. But DMD did it, the D language almost satisfied what I
need. Yes, you see, I am trying to use it to develop an operating system in D
language, and maybe it will be the first one written in D language.

As Chad mentioned, definitely not the first. But I don't know if
anything actually usable has been written yet...

While I was using C++ developing an os, the compiler can output the
platform-independent code. But DMD compiler can not do this, because it needs a
runtime library based on the present platform.
I have tried gdc, but I failed too. It prints the error below when I link:
ld: warning: cannot find entry symbol _mainCRTStartup; defaulting to 00401000

This first line isn't D-specific; a warning like this will likely pop up
for any code that doesn't link in a C library and doesn't specify an
alternative starting point for the program.
(Use ENTRY(<symbol>) in your linker script or add -e <symbol> or
--entry=<symbol> to your ld command line to set the entry point to some
function, or use a number instead to set it to a raw address)

These are indeed defined in the runtime library. They're used to
construct an import graph at runtime, in order to correctly handle
static constructors. Look at phobos/std/moduleinit.d or
tango/lib/compiler/{dmd,gdc}/genobj.d to see how this works.
If you're using DMD/Windows (Probably not if you're using ld), you may
also want to look at phobos/internal/minit.* (I haven't actually done
this, I use Linux).
Otherwise, you'll also need to run the constructors. They just
initialize a global symbol ('_Dmodule_ref' above) to link to a linked
list of module descriptors, so they don't need anything special as long
as the executable is loaded at the address it's linked at.
To run them on a Linux compiler, just call the function pointers stored
in the .ctors section of your executable.
If you're using native GDC on Windows, figure out how the Windows
runtime library is supposed to do this (It might be the same as on Linux).
If you're using GDC, you could also try to cross-compile it for
i386-elf, i586-elf, or similar. Again, I haven't done this myself so I
can't help much. The procedure for constructors will probably be much
the same as the one for Linux though.

Now I am wondering how can I link a platform-independent executable file?

(Assuming by "platform" you mean "operating system")
How about linking a your-os-dependent executable? :).

Do I need to rewrite the runtime library?
Or just I need to write a tiny runtime library like gc, moduleinit, object?

Whatever you do, you will need to include some of the functionality
provided by the runtime library yourself. However you don't need to
rewrite the entire runtime library, just the parts you actually use :).
Also, you can copy large parts of Phobos or Tango since much of the code
is OS-independent. Low-level routines for things like memory allocation
and anything else you use that normally requires system calls may need
to be rewritten to work for your OS.
I haven't actually ported the garbage collector myself, but it might not
be that hard. From the looks of it, it just uses a few routines that
depend on the OS and CPU architecture (to locate stacks and halt other
threads).
Note that you don't even necessarily need a GC. As long as you're
careful to delete any memory allocated manually you should be fine.
However, going this route means you'll probably want to stay away from
things that *might* reallocate[1], and check every library routine you
use to see whether it allocates anything and how to make sure it gets
deleted.
Like I said, I haven't gotten to porting the GC yet. Currently I just
allocate memory with no way to deallocate. Since I don't allocate very
much I haven't run out of memory yet :).
[1] For example: operator '~=' appends elements and other arrays to
arrays; it normally only reallocates when the (over-allocated) memory
for the array fills up. However it doesn't delete the original, since
other array references may still point to it (or parts of it).
Of course, this is technically just the behavior with Phobos and Tango.
If you're rewriting this anyway (as you might, since it allocates
memory) you can change this behavior any way you like.
If you don't want to use this operator for above reasons, you can delete
or comment out the relevant runtime routines (IIRC they're named
_d_arrayappend*) to turn use of it into a link-time error so you don't
accidentally use them (directly or in a library routine).
Something else that has similar behavior is the use of copy-on-write in
Phobos' std.string.

Hi, I'm an operating system developer. I've written a win32-compatible and
POSIX operating system, just for fun, but it can run many windows api programs.
My system is written in C, it is not readable and diffcult to manage. Now I am
looking for the new techniques to rewrite this os.

I'm writing a toy "OS kernel" for fun (in D), so I might be able to help.

I've ever thought for an own compiler and linker, it is so complicated to
develop an advanced one. But DMD did it, the D language almost satisfied what I
need. Yes, you see, I am trying to use it to develop an operating system in D
language, and maybe it will be the first one written in D language.

As Chad mentioned, definitely not the first. But I don't know if
anything actually usable has been written yet...

While I was using C++ developing an os, the compiler can output the
platform-independent code. But DMD compiler can not do this, because it needs a
runtime library based on the present platform.
I have tried gdc, but I failed too. It prints the error below when I link:
ld: warning: cannot find entry symbol _mainCRTStartup; defaulting to 00401000

This first line isn't D-specific; a warning like this will likely pop up
for any code that doesn't link in a C library and doesn't specify an
alternative starting point for the program.
(Use ENTRY(<symbol>) in your linker script or add -e <symbol> or
--entry=<symbol> to your ld command line to set the entry point to some
function, or use a number instead to set it to a raw address)

These are indeed defined in the runtime library. They're used to
construct an import graph at runtime, in order to correctly handle
static constructors. Look at phobos/std/moduleinit.d or
tango/lib/compiler/{dmd,gdc}/genobj.d to see how this works.
If you're using DMD/Windows (Probably not if you're using ld), you may
also want to look at phobos/internal/minit.* (I haven't actually done
this, I use Linux).
Otherwise, you'll also need to run the constructors. They just
initialize a global symbol ('_Dmodule_ref' above) to link to a linked
list of module descriptors, so they don't need anything special as long
as the executable is loaded at the address it's linked at.
To run them on a Linux compiler, just call the function pointers stored
in the .ctors section of your executable.
If you're using native GDC on Windows, figure out how the Windows
runtime library is supposed to do this (It might be the same as on Linux).
If you're using GDC, you could also try to cross-compile it for
i386-elf, i586-elf, or similar. Again, I haven't done this myself so I
can't help much. The procedure for constructors will probably be much
the same as the one for Linux though.

Now I am wondering how can I link a platform-independent executable file?

(Assuming by "platform" you mean "operating system")
How about linking a your-os-dependent executable? :).

Do I need to rewrite the runtime library?
Or just I need to write a tiny runtime library like gc, moduleinit, object?

Whatever you do, you will need to include some of the functionality
provided by the runtime library yourself. However you don't need to
rewrite the entire runtime library, just the parts you actually use :).
Also, you can copy large parts of Phobos or Tango since much of the code
is OS-independent. Low-level routines for things like memory allocation
and anything else you use that normally requires system calls may need
to be rewritten to work for your OS.
I haven't actually ported the garbage collector myself, but it might not
be that hard. From the looks of it, it just uses a few routines that
depend on the OS and CPU architecture (to locate stacks and halt other
threads).
Note that you don't even necessarily need a GC. As long as you're
careful to delete any memory allocated manually you should be fine.
However, going this route means you'll probably want to stay away from
things that *might* reallocate[1], and check every library routine you
use to see whether it allocates anything and how to make sure it gets
deleted.
Like I said, I haven't gotten to porting the GC yet. Currently I just
allocate memory with no way to deallocate. Since I don't allocate very
much I haven't run out of memory yet :).
[1] For example: operator '~=' appends elements and other arrays to
arrays; it normally only reallocates when the (over-allocated) memory
for the array fills up. However it doesn't delete the original, since
other array references may still point to it (or parts of it).
Of course, this is technically just the behavior with Phobos and Tango.
If you're rewriting this anyway (as you might, since it allocates
memory) you can change this behavior any way you like.
If you don't want to use this operator for above reasons, you can delete
or comment out the relevant runtime routines (IIRC they're named
_d_arrayappend*) to turn use of it into a link-time error so you don't
accidentally use them (directly or in a library routine).
Something else that has similar behavior is the use of copy-on-write in
Phobos' std.string.

I hope you can help me solve these puzzles, thanks!

I hope the above helps.

Thank you for your ideas, it's nice of you!
I did what you told, but I failed again.
When I tried to make a simple phonbos library( I removed a lot of code ), I got
lots of errors.
1. I wrote a simple object.d, it only contains a Object class and a ClassInfo
class. But DMD compiled failed.
dmd -c object.d
object.d(6): class object.Object D compiler and phobos/object.d are mismatched
object.d(29): class object.ClassInfo D compiler and phobos/object.d are
mismatched
2. I used GDC to do the same thing. But GDC was even worse:
M:\dmd\1>gdc -c object.d
Assertion failed: classinfo->structsize == CLASSINFO_SIZE, file ../../gcc-3.4.5-
20060117-1/gcc/d/dmd/toobj.c, line 417
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
object.d:25: internal compiler error: Aborted
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://www.mingw.org/bugs.shtml> for instructions.

Thank you for your ideas, it's nice of you!
I did what you told, but I failed again.
When I tried to make a simple phonbos library( I removed a lot of code ), I
got lots of errors.
1. I wrote a simple object.d, it only contains a Object class and a ClassInfo
class. But DMD compiled failed.
dmd -c object.d
object.d(6): class object.Object D compiler and phobos/object.d are mismatched
object.d(29): class object.ClassInfo D compiler and phobos/object.d are
mismatched

The compilers depend on some things in object.d being exactly as they
are in the version supplied with the compiler.
The ones I'm aware of:
1) The TypeInfo* classes must be present (and you probably shouldn't
change their data members either).
2) The same goes for ClassInfo (and possibly the Interface and
OffsetTypeInfo structs it uses, but I'm not sure). I'm sure you
shouldn't change the data members (Or at least their total size; but
it's probably best to keep their types and order intact as well or
they'll likely be useless). In fact, changes in data members probably
caused your second error message.
3) class Object must obviously be present. It may be a bad idea to add
data members, which might have caused that first error message.
In all of the above cases you can probably safely change the methods
though. I don't see why you would in the case of TypeInfo*, but you can
probably remove ClassInfo.{find,create}. Changing Object methods is
probably the most useful form of this (in fact, the one in Tango has
some changes; it removes Object.print and renames toString to toUtf8).
The implementations of TypeInfo_Class and TypeInfo_Interface use some
Object members though (toHash, opEquals and opCmp) so you might want to
keep that functionality intact, at least[1].
[1] Those TypeInfo members are used by associative arrays for keys IIRC,
so if you plan on using AAs with classes or interfaces as key types
you'll need them to work correctly. I'm not sure if AAs depend on the GC
though, so you may well want to avoid them if you don't plan on using GC
without checking and/or fixing that (AA operations are implemented in
library functions to which the compiler just inserts calls).

2. I used GDC to do the same thing. But GDC was even worse:
M:\dmd\1>gdc -c object.d
Assertion failed: classinfo->structsize == CLASSINFO_SIZE, file
../../gcc-3.4.5-
20060117-1/gcc/d/dmd/toobj.c, line 417

Actually, it isn't that much worse. It has the same cause as the second
compiler error DMD gave, (2) above. DMD used to have pretty much the
same error message, but may have changed it to the friendlier version
you got.
Like I said, don't change the data members of object.ClassInfo.
Also, note that GDC 0.23 used a different (shorter) ClassInfo than
recent DMD versions since it was based on an older DMD version; it will
give that error if you try to use it with the newer definition. GDC 0.24
came out yesterday with an updated version though, so that may not be a
problem in this case.
In reality you don't really need to change much in object.d. Before I
switched to Tango I had a slightly modified version that didn't change
data members, removed some final and static functions, but only changed
method definitions of virtual functions (mostly so they didn't depend on
C library functions like printf that I hadn't implemented, importing
some modules from my kernel to use in their place).
Currently I just use an unmodified object.d(i) from Tango (which isn't
the same as the one included with the compilers)
If you do plan to create your own version of object.d, the safest path
would probably be to copy the one that came with your compiler (or
Tango), and only change what you need to for it to compile and link
successfully (like use of above-mentioned C functions). Anything with
"notify" in the name seems to be safe to remove too.
In general, the way I used to create my own runtime library was to use
such a slightly-modified object.d, and not include anything else until
one of the following happened:
1) I needed a function that I didn't have in my source tree, or
2) The compiler generated a reference to data[2] or a function that is
normally defined in Phobos. (The way to tell if this is happening is to
see if you have any link errors, by the way)
Then find what you need and include that (or a ported or rewritten
version of it) into your source tree. To decode linker errors with _D*
names in them you might want to compile the example code from
std.demangle and pipe them through it. Then you can grep through the
source of one one of the standard libraries (Phobos or Tango) to see
what they do and how they are implemented there.
[2] TypeInfo data for simple types, Objects, or one-dimensional arrays
of those mostly.

This is great stuff, is there a wiki page or similar on the topic? If
not, this seems like a great start.

I don't know, I never looked for one[1]. This is all just from my
experience (maybe helped by some of what I've read on these newsgroups).
I didn't think it was too hard to figure out most of it, I just
basically kept reading Phobos sources and trying stuff until it worked :).
[1]: If you find (or start) one, feel free to add my stuff to it.

This is great stuff, is there a wiki page or similar on the topic? If
not, this seems like a great start.

I don't know, I never looked for one[1]. This is all just from my
experience (maybe helped by some of what I've read on these newsgroups).
I didn't think it was too hard to figure out most of it, I just
basically kept reading Phobos sources and trying stuff until it worked :).

Yeah, I'd do the same. It's nice to have someone else do all that
legwork for you though :)

[1]: If you find (or start) one, feel free to add my stuff to it.

I've never created a wiki page and don't have the first clue how, I hope
someone does though.
Regan

I don't know, I never looked for one[1]. This is all just from my
experience (maybe helped by some of what I've read on these newsgroups).
I didn't think it was too hard to figure out most of it, I just
basically kept reading Phobos sources and trying stuff until it worked :).
[1]: If you find (or start) one, feel free to add my stuff to it.

undefined reference to `_D11TypeInfo_Aa6__initZ
Would you tell me what's this reference about?
What's the use of it?

I'm not sure what exactly this is about, I've run in the the same
problems lately. I think it's some (static) initialization code for
TypeInfo, or at least that's what the mangled name suggests. Try to add
an implementation for init in the TypeInfo definition in object.d.

undefined reference to `_D11TypeInfo_Aa6__initZ
Would you tell me what's this reference about?
What's the use of it?

I'm not sure what exactly this is about, I've run in the the same
problems lately. I think it's some (static) initialization code for
TypeInfo, or at least that's what the mangled name suggests. Try to add
an implementation for init in the TypeInfo definition in object.d.

It's not a function. As I think I mentioned in my other post[1], though
perhaps not with so many words, this is part of what DMD emits when it
encounters a class called TypeInfo_Aa (The name used for the result type
of typeid(char[]).
_D<mangled_class_name>6__initZ is normally only the data used to
initialize a new object of that class when it's allocated, but DMD just
pretends it's the body of the object itself for TypeInfo instances it
emits references to when compiling code using typeid(T) or D-style
varargs (since TypeInfo-derived classes shouldn't change at runtime
anyway), so in this case it's more of a "statically allocated object".
Phobos and Tango use a similar trick, but coded with casts in the
library instead of hardwired into the compiler, to throw an
OutOfMemoryException without calling "new" (which obviously might not
work when you're running out of memory).
[1]: Which apparently took so long to type up that these posts were made
in the interim.

I'm not sure what exactly this is about, I've run in the the same
problems lately. I think it's some (static) initialization code for
TypeInfo, or at least that's what the mangled name suggests. Try to add
an implementation for init in the TypeInfo definition in object.d.

It's not a function. As I think I mentioned in my other post[1], though
perhaps not with so many words, this is part of what DMD emits when it
encounters a class called TypeInfo_Aa (The name used for the result type
of typeid(char[]).

I'm not sure what exactly this is about, I've run in the the same
problems lately. I think it's some (static) initialization code for
TypeInfo, or at least that's what the mangled name suggests. Try to add
an implementation for init in the TypeInfo definition in object.d.

perhaps not with so many words, this is part of what DMD emits when it
encounters a class called TypeInfo_Aa (The name used for the result type
of typeid(char[]).

I solved this problem by defining a function like below:
void _D11TypeInfo_Aa6__initZ()
{
while(1){}
}
But it is stupid to do such a thing.

Yes it is, because *it's not supposed to be a function*!
Just take phobos/std/typeinfo/ti_Ag.d[1], implement or replace memcmp
and std.string.cmp, and put it into your source tree. Problem solved.
[1] or the equivalent file from Tango, IIRC
tango/lib/compiler/{dmd,gdc}/typeinfo/ti_Ag.d

Now my object.d can be linked well.

It may link (assuming that function is declared extern(C)), but does it
do what it's supposed to do?
Try running something like this, compiled with your function above
linked in:
---
void test2(...) {
// Replace "writefln" with whatever function you use for text output
writefln(_arguments[0].toString);
}
void test() {
test("string");
}
---
The expected output when calling test() would be "char[]", but I'm
pretty sure it won't be if your function replaced the initialization
*data* of typeid(char[])...
(Hint: the first four bytes of that function probably don't point to a
meaningful vtable)

And I want to know how the classinfos get the information of the class, is it
stored in a initialized data section?

Yes, ClassInfo instances, like TypeInfo instances, are stored directly
in data sections by the compiler.

I wrote this program with my object.d

extern (C) int test()
{
B b = new B;
b.printok();
delete b;
return 2;
}
The result is
test(): passed
a.this(): passed
b.this(): passed
b.printok() : passed
b.~this(): not passed
a.~this(): not passed
I don't know why the two disconstructors are not passed everytime. When I
check the deallocator of the classinfo of these two classes, they are all empty
pointers.
This is my _d_delclass:

if (c.deallocator) //====failed at here!!!!!!!!!

I think that field is to store the overloaded delete operator, if any
(see http://www.digitalmars.com/d/1.0/class.html#ClassDeallocator).
Since you didn't overload it they're null (as they usually should be).
In Phobos _d_callfinalizer for classes allocated on the GC heap is
called somewhere from the '_gc.free' call that you replaced with a
regular 'free'. Putting an explicit call to
"_d_callfinalizer(cast(void*) p);" before the free should fix this, I think.

Hi, I solved one program now, you are right. My gdc source code is 2007-8-22
and my gdc executable files are a little old.
After I updated my gdc, I still have many troubles. This time I couldn't link
it. There are many undefined refereces. I don't know what the real work of
these functions do. I don't know whether is proper to write some dummy
functions for them.

Really, it's hard for me to read the phobos sources.

The easiest way to find out what a particular runtime function does is
really just to read the runtime sources provided with the compiler.
A tool like grep is really helpful here, especially since most runtime
functions (the ones starting with '_d_' aren't mangled, and their name
appears literally in the source.
By the way, The symbols looking like _D*TypeInfo* means you need some
extra typeinfo classes. They're in phobos/std/typeinfo and
tango/lib/compiler/{dmd,gdc}/typeinfo. You shouldn't need much more than
memcmp and a string-comparison function to get them to compile and link.
Looking at the missing the _d_* symbols, it looks like you're using the
synchronized keyword (on objects), which references the _d_monitor*
symbols. You'll either need to implement those for your platform so they
perform locking[1] or stop using synchronized.
_d_array{catn,append,appendc}T, _d_newarrayT, _d_delmemory may require
attention because they deal with dynamically allocated memory.
_d_dynamic_cast and the routines it requires can probably be lifted
straight from Phobos or Tango without any problems, they just read
ClassInfo structures and perform some pointer manipulations.
_d_array_bounds is just a function that gets called when array indices
are out of bounds. The standard implementation just throws an error but
you can perform any other kind of error handling here (printing a
message to screen and hanging can be used, for instance, as a debugging
tool that preserves the stack so you can use a debugger connected to an
emulator to find out where it happened)
[1]: IIRC they should be recursive, allowing the same thread to lock it
multiple times as long as it unlocks it as many times afterwards.

From what you said, I think you might have done a simple runtime library. If
so, would you send me one?

Wow! That's interesting!
You have implemented the exception handling. Haha, I've written the _try and
_catch which used in my old C kernel because there is no any keyword about
exceptions in pure C.
Have you done the memory management and the thread management in your present
kernel?
http://0ginr.com/xiaoxia/
This is web of my old os written in C&C++. There are screenshots on it. Also it
has a GUI and it can execute pe files, and a little win32 compatible( can run
the VC hello world ).
I like talking about the operating system teckniques with people who interests
in os developing too. My projects are all open source, because I like free
softwares.
This is my email: gdxxhg gmail.com
Mail me if we can develop os together!!

You have implemented the exception handling. Haha, I've written the _try and
_catch which used in my old C kernel because there is no any keyword about
exceptions in pure C.

As I tried to say (though perhaps not clearly enough) I didn't actually
implement most of it, I just used Tango which includes the relevant
runtime routines that are used (likely taken from Phobos). The only
thing I had to do was make sure my executable included the _deh* symbols
(IIRC they are emitted when the D main function is compiled, but I had
to update my linker script to keep them since I use the --gc-sections ld
switch that would otherwise have thrown them out).
The part about the _deh* symbols is probably DMD-only though, GDC uses
the default GCC exception handling IIRC.

Have you done the memory management and the thread management in your present
kernel?

My memory management currently is able to allocate and deallocate pages,
but my malloc/new just bumps a pointer, free/delete is a no-op and I
like I said I don't have a GC yet, so it's mostly allocate-only. Since
it's not really what you could seriously call a kernel[1] it's not
really a problem yet since I don't allocate nearly enough to fill the
memory.
Regarding threading, I have a way to start threads, but I currently have
no way to *end* threads (just a way mark them 'blocked' and switch to
another one :) ). And my scheduler is a simple round-robin skipping
blocked threads, defaulting to an idle thread if no unblocked threads
are found.
[1]: For instance: user-level code is mostly unimplemented currently,
though I've done some experiments with it a while back. Mostly because I
can't load programs from disk yet.

http://0ginr.com/xiaoxia/
This is web of my old os written in C&C++. There are screenshots on it. Also
it has a GUI and it can execute pe files, and a little win32 compatible( can
run the VC hello world ).

You're *that* guy? I really liked those screenshots when I first saw
them posted on osdev.org. (The rest of the site is pretty much
incomprehensible though :P)
My OS is currently text-only, though I have been looking into the VBE 3
protected-mode interface. Unfortunately the only way I can test code to
use it is to reboot my main computer so currently my OS just writes to
screen whether or not it's available in the BIOS. (It doesn't seem to be
supported by any emulator I could find)

I like talking about the operating system teckniques with people who interests
in os developing too. My projects are all open source, because I like free
softwares.
This is my email: gdxxhg gmail.com
Mail me if we can develop os together!!

For me it's mostly hobby so I'd kind of like to figure stuff out myself.
(also, you seem to be using Windows (judging by the prompt with your GDC
error message and the fact the error message indicates GDC/Mingw) but my
OS currently requires DMD/Linux to work, and I rather like ELF)
However if you post on the osdev.org forums I might be one of those who
answer.

For me it's mostly hobby so I'd kind of like to figure stuff out myself.
(also, you seem to be using Windows (judging by the prompt with your GDC
error message and the fact the error message indicates GDC/Mingw) but my
OS currently requires DMD/Linux to work, and I rather like ELF)
However if you post on the osdev.org forums I might be one of those who
answer.

Haha, have you ever answered my topics?
I am very grateful to you that you have help me solve many of my puzzles.
Thanks very much :)
Now I'm ready to write another os using GCC(asm & c & d language). It's a
microkernel and will support pe and elf executable programs. Of course it can
run linux and win32 programs.
I want to use D language because I like the code style and the easy way to
implement functions so the kernel can be extended easily. D code is nice!

Hi, I'm an operating system developer. I've written a win32-compatible and
POSIX operating system, just for fun, but it can run many windows api programs.
My system is written in C, it is not readable and diffcult to manage. Now I am
looking for the new techniques to rewrite this os.
I've ever thought for an own compiler and linker, it is so complicated to
develop an advanced one. But DMD did it, the D language almost satisfied what I
need. Yes, you see, I am trying to use it to develop an operating system in D
language, and maybe it will be the first one written in D language.
While I was using C++ developing an os, the compiler can output the
platform-independent code. But DMD compiler can not do this, because it needs a
runtime library based on the present platform.
I have tried gdc, but I failed too. It prints the error below when I link:
ld: warning: cannot find entry symbol _mainCRTStartup; defaulting to 00401000
hello.o(.text+0x18):hello.d: undefined reference to `_Dmodule_ref'
hello.o(.text+0x23):hello.d: undefined reference to `_Dmodule_ref'
hello.o(.data+0x0):hello.d: undefined reference to `_D10ModuleInfo6__vtblZ'
hello.o(.data+0x30):hello.d: undefined reference to `_D6object12__ModuleInfoZ'
Now I am wondering how can I link a platform-independent executable file?
Do I need to rewrite the runtime library?
Or just I need to write a tiny runtime library like gc, moduleinit, object?
I hope you can help me solve these puzzles, thanks!

If you take a closer look at OCD's or Titan's build process, you'll
eventually find out how to build your kernel. First thing: if you load
your kernel with Grub, you need an entry point in an Assembly file (or
at least I didn't succeed creating a valid Multiboot header inside a D
file), like here:
http://trac.brainsware.org/ocd/browser/branches/ocd-take2/ocd/nucleus/entry.asm
This file is proven to work. If you want to use it, please go ahead.. as
well as with 'all the other' (isn't so much yet, eh) OCD code, of course. :)
Anyways, your D entry point has to be extern(C) to remove the D name
mangling, afterwards you can operate in a D environment as much as you
please. Be sure to use structs where you can, as (dynamically
instantiated) classes can lead to GC invocations. Also avoid dynamic
arrays or associative arrays.. but Frits mentioned that all already I think.
Would be nice if you keep us informed about your progress!
Kind regards,
Alex

Hi, I'm an operating system developer. I've written a win32-compatible and
POSIX operating system, just for fun, but it can run many windows api programs.
My system is written in C, it is not readable and diffcult to manage. Now I am
looking for the new techniques to rewrite this os.
I've ever thought for an own compiler and linker, it is so complicated to
develop an advanced one. But DMD did it, the D language almost satisfied what I
need. Yes, you see, I am trying to use it to develop an operating system in D
language, and maybe it will be the first one written in D language.
While I was using C++ developing an os, the compiler can output the
platform-independent code. But DMD compiler can not do this, because it needs a
runtime library based on the present platform.
I have tried gdc, but I failed too. It prints the error below when I link:
ld: warning: cannot find entry symbol _mainCRTStartup; defaulting to 00401000
hello.o(.text+0x18):hello.d: undefined reference to `_Dmodule_ref'
hello.o(.text+0x23):hello.d: undefined reference to `_Dmodule_ref'
hello.o(.data+0x0):hello.d: undefined reference to `_D10ModuleInfo6__vtblZ'
hello.o(.data+0x30):hello.d: undefined reference to `_D6object12__ModuleInfoZ'
Now I am wondering how can I link a platform-independent executable file?
Do I need to rewrite the runtime library?
Or just I need to write a tiny runtime library like gc, moduleinit, object?
I hope you can help me solve these puzzles, thanks!

If you take a closer look at OCD's or Titan's build process, you'll
eventually find out how to build your kernel. First thing: if you load
your kernel with Grub, you need an entry point in an Assembly file (or
at least I didn't succeed creating a valid Multiboot header inside a D
file), like here:
http://trac.brainsware.org/ocd/browser/branches/ocd-take2/ocd/nucleus/entry.asm
This file is proven to work. If you want to use it, please go ahead.. as
well as with 'all the other' (isn't so much yet, eh) OCD code, of course. :)
Anyways, your D entry point has to be extern(C) to remove the D name
mangling, afterwards you can operate in a D environment as much as you
please. Be sure to use structs where you can, as (dynamically
instantiated) classes can lead to GC invocations. Also avoid dynamic
arrays or associative arrays.. but Frits mentioned that all already I think.
Would be nice if you keep us informed about your progress!
Kind regards,
Alex

Hi, What you said is the basic things, I have all done now. I had a look at
the OCD kernel code, there's no class using in it, but intead of struct.

Using structs is intentional; structs don't require heap allocation,
thus the kernel's stack is used for those. Given how flexible structs
are in D, you can use them just like classes, which is a very handy
advantage.
Of course, as soon as dynamic heap allocation is available, classes can
be used like always. But this requires a basic memory management, which
is not yet built into OCD.

I think a class is important for wrapping the functions, and template is
useful too.

tried to use it for several memory operational functions (memcpy,
memmov), but I didn't look into it too deep, which is why I just went
for pointers nevertheless.

I wrote an object.d, see below:
...

You can use Tango's object.d[i] almost directly and provide the
necessary functions in your code, like malloc and friends.

I used DMD to compile it, a fatal error occured and the DMD-self exited.

What operating system are you using? I don't think it's possible to
compile ELF binaries on Windows with DMD. (Given the fact that you use
ELF, which I assume.) I suggest using GDC + binutils (ld). I don't know
if you're experienced with LD scripts - if not, there's a .ld file in
the repository which *should* work. It is yet to be changed to include
all D specific sections et al.
Kind regards,
Alex

I wrote an object.d, see below:
module object;
/// Standard boolean type.
alias bool bit;
/**
* An unsigned integral type large enough to span the memory space. Use for
* array indices and pointer offsets for maximal portability to
* architectures that have different memory address ranges. This is
* analogous to C's size_t.
*/
alias ulong size_t;
/**
* A signed integral type large enough to span the memory space. Use for
* pointer differences and for size_t differences for maximal portability to
* architectures that have different memory address ranges. This is
* analogous to C's ptrdiff_t.
*/
alias long ptrdiff_t;
alias ulong hash_t;

The above three are the definitions DMD uses in a "version(X86_64)"
block, but since it doesn't yet even support 64-bit code this isn't ever
used by DMD itself. DMD uses
---
alias uint size_t;
alias int ptrdiff_t;
alias uint hash_t;
---
(Though the last one is probably harmless)
[snip lots]

=========END=========
I used DMD to compile it, a fatal error occured and the DMD-self exited.

You forgot to copy over (and port where necessary, which isn't much) the
TypeInfo* classes. They need (replacements for) std.string.cmp,
std.string.toString(size_t), memcmp and memcpy. And you'll need dynamic
memory allocation to be implemented for TypeInfo_StaticArray.swap, but
it deletes allocated memory (if any) at the end so a GC isn't required.
But like I said, I found it easier to just use Tango :).