www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Can dmd compile with my own runtime library?

reply Huang F Guan <gdxxhg gmail.com> writes:
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!
Aug 21 2007
next sibling parent reply Chad J <gamerChad _spamIsBad_gmail.com> writes:
Huang F Guan wrote:
 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.html http://www.dsource.org/projects/osian http://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).
Aug 21 2007
parent Huang F Guan <gdxxhg gmail.com> writes:
Chad J Wrote:
 
 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.html
 http://www.dsource.org/projects/osian
 http://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.
Aug 21 2007
prev sibling next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Huang F Guan wrote:
 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)
 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'

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.
Aug 22 2007
parent reply Huang F Guan <gdxxhg gmail.com> writes:
Frits van Bommel Wrote:

 Huang F Guan wrote:
 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)
 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'

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.
Aug 23 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Huang F Guan wrote:
 Frits van Bommel Wrote:

 
 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.
Aug 23 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
This is great stuff, is there a wiki page or similar on the topic?  If 
not, this seems like a great start.

Regan
Aug 23 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Regan Heath wrote:
 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.
Aug 23 2007
next sibling parent Regan Heath <regan netmail.co.nz> writes:
Frits van Bommel wrote:
 Regan Heath wrote:
 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
Aug 23 2007
prev sibling parent reply Huang F Guan <gdxxhg gmail.com> writes:
Frits van Bommel Wrote:

 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.

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. ld: warning: cannot find entry symbol _mainCRTStartup; defaulting to 00401000 object.o(.text+0xfe):object.d: undefined reference to `_d_monitorenter' object.o(.text+0x16d):object.d: undefined reference to `_d_monitorexit' object.o(.text+0x244):object.d: undefined reference to `_d_array_bounds' object.o(.text+0x27b):object.d: undefined reference to `_d_array_bounds' object.o(.text+0x2fa):object.d: undefined reference to `_d_array_bounds' object.o(.text+0x31f):object.d: undefined reference to `_d_monitorexit' object.o(.text+0x347):object.d: undefined reference to `_d_monitorenter' object.o(.text+0x3af):object.d: undefined reference to `_d_monitorexit' object.o(.text+0x431):object.d: undefined reference to `_d_monitorenter' object.o(.text+0x457):object.d: undefined reference to `_d_monitorexit' object.o(.text+0x5cb):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0x623):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0x85e):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0xaf2):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0xaf7):object.d: undefined reference to `_d_arraycatnT' object.o(.text+0xb37):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0xcca):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0xccf):object.d: undefined reference to `_d_arraycatnT' object.o(.text+0xd0f):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0x1015):object.d: undefined reference to `_D6string8toStringFaZAa' object.o(.text+0x105e):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x1063):object.d: undefined reference to `_d_arraycatnT' object.o(.text+0x1082):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x1087):object.d: undefined reference to `_d_arraycatnT' object.o(.text+0x10b4):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x10b9):object.d: undefined reference to `_d_arraycatnT' object.o(.text+0x10fb):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0x139d):object.d: undefined reference to `_D11TypeInfo_Av6__initZ' object.o(.text+0x13a2):object.d: undefined reference to `_d_newarrayT' object.o(.text+0x1438):object.d: undefined reference to `_d_delmemory' object.o(.text+0x151e):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x1523):object.d: undefined reference to `_d_arraycatnT' object.o(.text+0x1542):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x1547):object.d: undefined reference to `_d_arraycatnT' object.o(.text+0x1574):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x1579):object.d: undefined reference to `_d_arraycatnT' object.o(.text+0x15bb):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0x16be):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x16c3):object.d: undefined reference to `_d_arraycatnT' object.o(.text+0x1703):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0x17af):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x17b4):object.d: undefined reference to `_d_arraycatnT' object.o(.text+0x17f4):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0x18bc):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0x1b11):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0x1dbd):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0x20f3):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x20f8):object.d: undefined reference to `_d_arrayappendcTp' object.o(.text+0x2120):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x2125):object.d: undefined reference to `_d_arrayappendT' object.o(.text+0x2150):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x2155):object.d: undefined reference to `_d_arrayappendT' object.o(.text+0x2197):object.d: undefined reference to `_d_dynamic_cast' object.o(.text+0x2203):object.d: undefined reference to `_d_array_bounds' object.o(.text+0x224c):object.d: undefined reference to `_d_array_bounds' object.o(.text+0x23f0):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x23f5):object.d: undefined reference to `_d_arraycatnT' object.o(.text+0x2604):object.d: undefined reference to `_D11TypeInfo_Aa6__initZ' object.o(.text+0x2609):object.d: undefined reference to `_d_arraycatnT' Really, it's hard for me to read the phobos sources. From what you said, I think you might have done a simple runtime library. If so, would you send me one?
Aug 23 2007
next sibling parent reply Alexander Panek <alexander.panek brainsware.org> writes:
Be sure to use -release to disable array bounds checking et al!
Aug 23 2007
parent reply Huang F Guan <gdxxhg gmail.com> writes:
undefined reference to `_D11TypeInfo_Aa6__initZ

Would you tell me what's this reference about?

 What's the use of it?
Aug 23 2007
parent reply Alexander Panek <alexander.panek brainsware.org> writes:
Huang F Guan wrote:
 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.
Aug 23 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Alexander Panek wrote:
 Huang F Guan wrote:
 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.
Aug 23 2007
parent reply Huang F Guan <gdxxhg gmail.com> writes:
Frits van Bommel Wrote:

 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 solved this problem by defining a function like below: void _D11TypeInfo_Aa6__initZ() { while(1){} } But it is stupid to do such a thing. Now my object.d can be linked well. And I want to know how the classinfos get the information of the class, is it stored in a initialized data section? I wrote this program with my object.d class A{ private int a; this() { a = 0x00111111; } ~this() { a= 0x88111111; } } class B : A { private int b; this() { b = 0x00222222; super(); } int printok() { b = 0x00333333; return b; } ~this() { b = 0x88222222; } } 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: void _d_delclass(Object *p) { if (*p) { //debug (PRINTF) printf("_d_delclass(%p)\n", *p); ClassInfo **pc = cast(ClassInfo **)*p; if (*pc) { ClassInfo c = **pc; if (c.deallocator) //====failed at here!!!!!!!!! { _d_callfinalizer(cast(void *)(*p)); fp_t fp = cast(fp_t)c.deallocator; (*fp)(*p); // call deallocator *p = null; return; } } free(cast(void*)(*p)); //passed. *p = null; } }
Aug 23 2007
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Huang F Guan wrote:
 Frits van Bommel Wrote:
 
 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.
Aug 24 2007
prev sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Huang F Guan wrote:
 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? 

Like I said, I switched to just using Tango. It's quite easy to port. In fact, looking at my diff viewer, I mostly just copied the posix.mak files to MyOS.mak and added -D__MyOS__ to CFLAGS and -version=MyOS to the other *FLAGS and then commented and versioned out some code that needed stuff I didn't support yet (locking) and/or didn't need anyway (floating point support). In my kernel sources I added an empty "extern(C) void thread_init()" (with TODO comment), implemented malloc, calloc and free using my kernel allocation functions, and added this into a file called init.d: --- import multiboot; import console; import mem.init; extern (C) bool rt_init( void delegate( Exception ) dg = null ); extern (C) bool rt_term( void delegate( Exception ) dg = null ); int main(char[][] args); extern(C) void init() { extern(C) void rtinitExceptionHandler(Exception e) { writefln("Uncaught exception in runtime: {}", e); throw new Exception("Exception during runtime initialization", e); } try { mem_init(); rt_init(&rtinitExceptionHandler); /// Shouldn't return... main(multiboot.commandLine()); } catch (Exception e) { writefln("Uncaught exception: {}", e); } catch (Object o) { writefln("Uncaught non-Exception exception: {}", o); } writeln("main() returned, halting processor."); for(;;) asm { cli; hlt; } } --- Notes: * the imports at the top are some of my kernel modules. * mem_init also initializes my multiboot module which it uses to get the memory address ranges that are free (the elf header is also parsed to find where kernel code and static data is located, and multiboot modules should also be taken into account if you support them) * 'init' is called by my asm code after it calls all the pointers in the .ctors section. * 'rt_init' is from Tango and calls the static constructors of all modules that have one. * IIRC exception handling "just worked"[1], but make sure you catch exceptions in your interrupt handlers and the top-level function in every thread. * the write* functions are *really* easy to implement with the help of tango.text.convert.Layout and a way to print characters to the screen :). [1]: I already knew to not throw away the .deh* sections of my executable in my linker script. Speaking of which, here it is: --- OUTPUT_FORMAT("elf32-i386") ENTRY(start) phys = 0x00100000; virt = 0xC0000000; SECTIONS { . = phys + virt; /* Multiboot Header */ mb-header : AT(ADDR(mb-header) - virt) { /* Multiboot header, must be 4-byte aligned and in first 8k of file. */ . = ALIGN(4); KEEP(*(mb-header)) /* not referenced by code, just by bootloader (i.e. GRUB) */ } .text : AT(ADDR(.text) - virt) { code_begin = .; *(.text* .gnu.linkonce.t*) } . = ALIGN(4096); .data : AT(ADDR(.data) - virt) { *(.data* .gnu.linkonce.d*) } /* For some reason .ctors isn't marked read-only, so group with .data */ .ctors : AT(ADDR(.ctors) - virt) { start_ctors = .; KEEP(*(.ctor*)) /* not referenced except through surrounding labels */ end_ctors = .; } . = ALIGN(4096); /* Read-only data right before uninitialized data, as that contains the * (down-growing) stack. This way, we can put the read-only data on a * non-writable page and catch stack overflows */ .rodata : AT(ADDR(.rodata) - virt) { *(.rodata*) } /* Exception handling data */ .deh_eh : AT(ADDR(.deh_eh) - virt) { _deh_beg = .; KEEP(*(.deh_beg)) KEEP(*(.deh_eh)) _deh_end = .; KEEP(*(.deh_end)) } . = ALIGN(4096); .bss : AT(ADDR(.bss) - virt) { *(.bss*) } /DISCARD/ : { *(.comment) } kernel_end = .; } --- Also note that my initial stack is in .bss, at the start, and that right before .bss is read-only data. One of my modules sets the pages containing the latter to read-only so stack overflows are detected. This is optional and putting all read-only stuff together may keep the kernel size down a bit. I also put the multiboot header in its own section to make sure it's put as far to the front of the executable as possible. My startup asm (that declares the 'start' entry symbol) performs some initialization including stack, GDT (+ segment registers) and (simple, 1 4MB-page mapped at both 0 and 0xC000_0000) paging (and assigning the multiboot signature and data address to variables defined in my 'multiboot' module), calls every function pointer from start_ctors to end_ctors (as defined in the linker script), then calls my 'init' function posted above.
Aug 23 2007
parent reply Huang F Guan <gdxxhg gmail.com> writes:
Frits van Bommel Wrote:
 
 Like I said, I switched to just using Tango. It's quite easy to port. In 
 fact, looking at my diff viewer, I mostly just copied the posix.mak 
 files to MyOS.mak and added  -D__MyOS__ to CFLAGS and -version=MyOS to 
 the other *FLAGS and then commented and versioned out some code that 
 needed stuff I didn't support yet (locking) and/or didn't need anyway 
 (floating point support).
 In my kernel sources I added an empty "extern(C) void thread_init()" 
 (with TODO comment), implemented malloc, calloc and free using my kernel 
 allocation functions, and added this into a file called init.d:
 ---
 import multiboot;
 import console;
 import mem.init;
 
 extern (C) bool rt_init( void delegate( Exception ) dg = null );
 extern (C) bool rt_term( void delegate( Exception ) dg = null );
 
 int main(char[][] args);
 
 extern(C) void init() {
 
      extern(C) void rtinitExceptionHandler(Exception e) {
          writefln("Uncaught exception in runtime: {}", e);
          throw new Exception("Exception during runtime initialization", e);
      }
 
      try {
          mem_init();
 
          rt_init(&rtinitExceptionHandler);
 
          /// Shouldn't return...
          main(multiboot.commandLine());
 
      } catch (Exception e) {
          writefln("Uncaught exception: {}", e);
      } catch (Object o) {
          writefln("Uncaught non-Exception exception: {}", o);
      }
      writeln("main() returned, halting processor.");
      for(;;) asm { cli; hlt; }
 }
 ---

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!!
Aug 23 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Huang F Guan wrote:
 Frits van Bommel Wrote:

 
 Wow! That's interesting! 

Thanks.
 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.
Aug 23 2007
parent Huang F Guan <gdxxhg gmail.com> writes:
Frits van Bommel Wrote:
 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!
Aug 23 2007
prev sibling parent reply Alexander Panek <alexander.panek brainsware.org> writes:
Huang F Guan wrote:
 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
Aug 23 2007
parent reply Huang F Guan <gdxxhg gmail.com> writes:
Alexander Panek Wrote:

 Huang F Guan wrote:
 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. I think a class is important for wrapping the functions, and template is useful too. 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; /****************** * All D class objects inherit from Object. */ class Object { void print() { //printf("%.*s\n", toString()); } char[] toString() { //return null; //test while(1)continue; return this.classinfo.name; } /** * Compute hash function for Object. */ hash_t toHash() { // BUG: this prevents a compacting GC from working, needs to be fixed while(1)continue; return cast(hash_t)cast(void *)this; } int opCmp(Object o) { //test while(1)continue; return 1; //throw new Error("need opCmp for class " ~ this.classinfo.name); } int opEquals(Object o) { while(1)continue; return cast(int)(this is o); } } /** * Information about an interface. * A pointer to this appears as the first entry in the interface's vtbl[]. */ struct Interface { ClassInfo classinfo; /// .classinfo for this interface (not for containing class) void *[] vtbl; int offset; /// offset to Interface 'this' from Object 'this' } /** * Array of pairs giving the offset and type information for each * member in an aggregate. */ struct OffsetTypeInfo { size_t offset; /// Offset of member from start of object //TypeInfo ti; /// TypeInfo for this member } class ClassInfo : Object { byte[] init; /** class static initializer * (init.length gives size in bytes of class) */ char[] name; /// class name void *[] vtbl; /// virtual function pointer table Interface[] interfaces; /// interfaces this class implements ClassInfo base; /// base class void *destructor; void (*classInvariant)(Object); uint flags; // 1: // IUnknown // 2: // has no possible pointers into GC memory // 4: // has offTi[] member // 8: // has constructors void *deallocator; OffsetTypeInfo[] offTi; void function(Object) defaultConstructor; // default Constructor /************* * Search all modules for ClassInfo corresponding to classname. * Returns: null if not found */ static ClassInfo find(char[] classname) { while(1) continue; //foreach (m; ModuleInfo.modules()) //{ // //writefln("module %s, %d", m.name, m.localClasses.length); // foreach (c; m.localClasses) // { // //writefln("\tclass %s", c.name); // if (c.name == classname) // return c; // } //} return null; } /******************** * Create instance of Object represented by 'this'. */ Object create() { if (flags & 8 && !defaultConstructor) return null; Object o = _d_newclass(this); if (flags & 8 && defaultConstructor) { defaultConstructor(o); } return o; } } extern(C): Object _d_newclass(Object ci) { void *p; p = cast(void*)0x22222222; //if (ci.flags & 1) // if COM object //{ //p = std.c.stdlib.malloc(ci.init.length); //if (!p) // _d_OutOfMemory(); //} // Initialize it //(cast(byte*)p)[0 .. ci.init.length] = ci.init[]; //printf("initialization done\n"); return cast(Object)p; } =========END========= I used DMD to compile it, a fatal error occured and the DMD-self exited.
Aug 23 2007
next sibling parent reply Alexander Panek <alexander.panek brainsware.org> writes:
Huang F Guan wrote:
 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
Aug 23 2007
parent reply Huang F Guan <gdxxhg gmail.com> writes:
Alexander Panek Wrote:
 
 You can use Tango's object.d[i] almost directly and provide the 
 necessary functions in your code, like malloc and friends.
 

I have Tango's source code, I only found the file object.di, but it is a declaration file, and not a implementaion file. How can I use this file?
Aug 23 2007
parent Alexander Panek <alexander.panek brainsware.org> writes:
Huang F Guan wrote:
 Alexander Panek Wrote:
 You can use Tango's object.d[i] almost directly and provide the 
 necessary functions in your code, like malloc and friends.

I have Tango's source code, I only found the file object.di, but it is a declaration file, and not a implementaion file. How can I use this file?

You actually don't need more (to make it compile). The implementation file itself is somewhere in [tango/]lib/compiler/<yourcompiler>/ IIRC.
Aug 23 2007
prev sibling parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Huang F Guan wrote:
 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 :).
Aug 23 2007