Providing C++ Runtime support for Kernel

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Providing C++ Runtime support for Kernel

Post by Pype.Clicker »

looking at the mangled symbols will just give you the function pointers to the constructors, but isn't the .ctor and .dtor list giving more informations ? don't they tell which constructor should be invoked together with the memory address that will receive the object ?
whyme_t

Re:Providing C++ Runtime support for Kernel

Post by whyme_t »

Well, I'm not an asm guru :)

I thought, or though I could be mistaken, that It was just a case adding the code to call the static / global ctors and dtors, as the code is omitted when compilling for a free standing environment. The only time we would have to allocate memory for the objects would be for dynamic objects, which would then need new and delete support code added.

Could some one explain the information that is in the .ctor and .dtor sections here?

The section headers.

Code: Select all

objdump -h example1.o

example1.o:     file format coff-go32

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         000003b0  00000000  00000000  00000104  2**4
                  CONTENTS, ALLOC, LOAD, RELOC, CODE
  1 .data         00000000  000003b0  000003b0  00000000  2**4
                  ALLOC, LOAD, DATA
  2 .bss          00000220  000003b0  000003b0  00000000  2**2
                  ALLOC
  3 .ctors        00000004  000005d0  000005d0  000004b4  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, DATA
  4 .dtors        00000004  000005d4  000005d4  000004b8  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, DATA
  5 .comment      00000010  000005d8  000005d8  000004bc  2**2
                  CONTENTS, DEBUGGING
Assembler for .ctor and .dtor sections.
What is this code doing?

Code: Select all

objdump -D example1.o

<snip>
Disassembly of section .data:
Disassembly of section .ctors:

000005d0 <.ctors>:
 5d0:   70 03                   jo     5d5 <.dtors+0x1>
        ...
Disassembly of section .dtors:

000005d4 <.dtors>:
 5d4:   8a 03                   mov    (%ebx),%al
        ...
I create the list in my linker script.

Code: Select all

<snip>
.data  : {
    __CTOR_LIST__ = .; LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) *(.ctors) LONG(0) __CTOR_END__ = .; __DTOR_LIST__ = .; LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) *(.dtors) LONG(0) __DTOR_END__ = .; 
    data = .; _data = .; __data = .;
    *(.data)
    . = ALIGN(4096);
  }
</snip>
So in my C support code, I just walk __CTOR_LIST__ calling the constructors as I go along. The first value in the list is the number of constructors.

Code: Select all

void __do_global_init()
{
   extern void (*_CTOR_LIST__)() ;

   void (**constructor)() = &_CTOR_LIST__ ;

   int total = *(int *)constructor ;

   constructor++ ;

   unsigned int i ;

   for(i=0; i<=total; i++, constructor++)
   {
      (*constructor)() ;
   }
I'm trying to get all this all sorted out, so I can write some tutorials on how to write a kernel in C++ :)
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Providing C++ Runtime support for Kernel

Post by Pype.Clicker »

with 4 bytes each, it is unlikely that your .ctor section actually hold code :(
whyme_t

Re:Providing C++ Runtime support for Kernel

Post by whyme_t »

When I call __do_global_init() it does successfully call all the global / static objects constructors.

Could the 4 bytes be 2 pointers, one to the ctor, one to the dtor? this example only had one global object.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Providing C++ Runtime support for Kernel

Post by Pype.Clicker »

yep. that's probably what they are ... what i miss here is how they know *what* object is to be set up ... i mean, if instead of 1 object i do have 3 of them, how much entries in .dtor will there have ? and what will they point to ? some custom function call like

Code: Select all

__build_classXYZ_object(&XYZ_instance_target);
for every instanciated object ?
whyme_t

Re:Providing C++ Runtime support for Kernel

Post by whyme_t »

sections with 3 global objects of type OStream.

Code: Select all

objdump -h example1.o

example1.o:     file format coff-go32

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000420  00000000  00000000  00000104  2**4
                  CONTENTS, ALLOC, LOAD, RELOC, CODE
  1 .data         00000000  00000420  00000420  00000000  2**4
                  ALLOC, LOAD, DATA
  2 .bss          00000660  00000420  00000420  00000000  2**2
                  ALLOC
  3 .ctors        00000004  00000a80  00000a80  00000524  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, DATA
  4 .dtors        00000004  00000a84  00000a84  00000528  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, DATA
  5 .comment      00000010  00000a88  00000a88  0000052c  2**2
                  CONTENTS, DEBUGGING
This is a list of all the mangled symbol names in example1.o

Code: Select all

__Z41__static_initialization_and_destruction_0ii
__ZSt4endl
__GLOBAL__I__ZNSt7OStreamC2Ev
__GLOBAL__D__ZNSt7OStreamC2Ev
__ZNSt7OStreamC2Ev
__ZNSt7OStream5clearEv
__ZNSt7OStreamC1Ev
__ZNSt7OStreamD2Ev
__ZNSt7OStreamD1Ev
__ZNSt7OStreamlsEPc
__ZNSt7OStreamlsEc
__ZNSt7OStream5flushEv
__ZSt4cout
__ZSt5cout2
__ZSt5cout3
__ZN1XC2Ev
__ZN1XC1Ev
__ZN1XD2Ev
__ZN1XD1Ev
__ZN1YC2Ev
__ZN1YC1Ev
__ZN1YD2Ev
__ZN1YD1Ev
class OStream contains the following methods

Code: Select all

      OStream() ;
      ~OStream() ;
      OStream& operator << (char * string) ;
      OStream& operator << (const char manipulator) ;
      void flush() ;
      void clear() ;
The global objects are called cout, cout2, and cout3.
If you look though the symbols, you can pick out most of the functions. I'm sure the .ctor section holds a pointer to each constructor, which has a standard prefix to show that it is a gloab / static constructor.

Any ideas?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Providing C++ Runtime support for Kernel

Post by Pype.Clicker »

what you could do is look at the value stored in the 2x4 bytes of .ctors and .dtors and see which symbol it matches (if any), then trying to disassemble from this address ...
whyme_t

Re:Providing C++ Runtime support for Kernel

Post by whyme_t »

ok, this is what I did.

Code: Select all

class X
{
public:
   X() {};
   ~X() {};
};

X x ;

int main(void){}
compiled using gxx -c x.cpp -ffreestanding -nostdlib -fno-builtin -fno-rtti -fno-exceptions

Then I used objdump -D x.o, to display assembler contents of all sections.

Code: Select all

00000000 <_main>: 
(some asm code)
00000018 <__Z41__static_initialization_and_destruction_0ii>:
(some asm code)
0000005e <__GLOBAL__I_x>:
  5e:   55                      push   %ebp
(some asm code)
00000078 <__GLOBAL__D_x>:
  78:   55                      push   %ebp
(some asm code)
Disassembly of section .ctors:
000000c4 <.ctors>:
  c4:   5e                      pop    %esi
  c5:   00 00                   add    %al,(%eax)
        ...
Disassembly of section .dtors:
000000c8 <.dtors>:
  c8:   78 00                   js     ca <.dtors+0x2>
        ...
Now would I be wrong in thinking that the 5e in the .ctor section is a pointer to the first instruction in __GLOBAL__I_x ?(which I assume is the initialisation code), and in turn that the 78 in the .dtor section points to the first instruction in __GLOBAL__D_x?

So if I look at some object code produced by other compilers, I should be able to see if it would be possible to write a tool which parses object files, looking for their version of __GLOBAL__I and then add's the .ctor and .dtor sections. Thus providing a more portable solution to using C++ in the Kernel.... or am I wrong somewhere? ;)
Tim

Re:Providing C++ Runtime support for Kernel

Post by Tim »

Instead of playing with the disassembly and guessing what goes on, why not just look up the libc startup code provided with your compiler? You can then copy it and paste it into your own libc, and it will work.
whyme_t

Re:Providing C++ Runtime support for Kernel

Post by whyme_t »

Yup, I've already looked at that source, and done something very similar. :) I've already it got it working with my compiler, because my compiler uses the .ctor and .dtor sections.

I'm just seeing if there is a way of doing it no matter what compiler you use.

Hence my idea for a tool which could add the sections.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Providing C++ Runtime support for Kernel

Post by Pype.Clicker »

Here's what i found so far:

the .ctor section actually holds one pointer to __GLOBAL_I_x, and the .dtor section holds one pointer to __GLOBAL_D_x. both these function call __static_initialisation_and_destruction(int,int) which has a list of instruction that actually call the initializer for every object (calling the right constructors with the address of the object to be initialized)

what is surprising is that when you have several static objects in the same file, there is still only one .ctors entry ... i think this is because the compiler is smart enough and collect all the global initialisation he sees from example.cpp into the same __static_initialisation_and_destruction code. The reason why .ctors can contain several entries is likely to be that there could be other __static_init ... from other object files.

Thus, imho, calling the pointers located in .ctors section before calling main() and calling the pointers in .dtors after main() returns is safe.

to tim : reverse engineering is sometimes easier to do than browsing Stallmans & co sources ;)
Tim

Re:Providing C++ Runtime support for Kernel

Post by Tim »

Pype.Clicker wrote:to tim : reverse engineering is sometimes easier to do than browsing Stallmans & co sources ;)
Agree completely! ;)
whyme_t

Re:Providing C++ Runtime support for Kernel

Post by whyme_t »

ok everyone, I've been busy writing my C++ Kernel, and I've just finished my first draft of parts 1 and 2 of my tutorials, and I've finished the code for parts 3-7.

Could you check it out and give me some constructive criticism. This is my first attempt at writing a tutorial.

http://www.invalidsoftware.net/os/

thanxs in advance. :)
Tom

Re:Providing C++ Runtime support for Kernel

Post by Tom »

you mis-typed somthing for the page title...you typed in

Writting

still reading...
_PlayOS

Re:Providing C++ Runtime support for Kernel

Post by _PlayOS »

Hi,

Excellent stuff, I cannot wait for the rest of the tutorial parts.

Two prblems though, Video.h dosen't exist, you declare your class in Kernel.h, but in video.cpp and kernel.cpp you have #include "video.h" other than that, excellent work.
Post Reply