Bug in C++ bare bones ctor/dtor examples?

All about the OSDev Wiki. Discussions about the organization and general structure of articles and how to use the wiki. Request changes here if you don't know how to use the wiki.
Post Reply
TylerH
Member
Member
Posts: 285
Joined: Tue Apr 13, 2010 8:00 pm
Contact:

Bug in C++ bare bones ctor/dtor examples?

Post by TylerH »

http://gcc.gnu.org/onlinedocs/gccint/In ... ation.html says that the list starts and ends with a non-function-pointer value. The examples don't skip them.

It seems unlikely to me that there would be a bug in a bare bones, since (I assume) they're the most view articles. Is the GCC documentation wrong?
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Bug in C++ bare bones ctor/dtor examples?

Post by Combuster »

As far as I can tell, it's an implementation detail. I define crtbegin.asm/crtend.asm as just a bunch of labels, which is something that not all linkers of all time might have liked. It would explain why there would be a necessity for leading and trailing "garbage". I couldn't be bothered however to locate the source for the crtbegin/crtend linux uses to see what's actually being put there.

In any case, barebones doesn't need it, I don't need it, you may find no reason to need it either.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: Bug in C++ bare bones ctor/dtor examples?

Post by xenos »

I guess one can easily test whether gcc produces this "garbage" by having a look at the contents of the ctor/dtor lists. No matter whether it is necessary for one kernel or not for another - if it is present, one must be careful not to call something that is not a constructor. According to the gcc docs,
gcc wrote:Each list always begins with an ignored function pointer (which may hold 0, −1, or a count of the function pointers after it, depending on the environment). This is followed by a series of zero or more function pointers to constructors (or destructors), followed by a function pointer containing zero.
I don't use global C++ objects in my kernel, so it would take me some time to write some simple test code, but I remember that I once worked on an OS named Trion, which actually relied on the first entry of the ctor/dtor list being the number of ctors/dtors, as you can see from this code:

Code: Select all

// Walk and call the constructors in the ctor_list
void ExecuteConstructors(void)
{
	// Get a copy of the contructor list
	void (**constructor)(void) = &ctorStart;

	// The constructor list first contains an integer
	// containing the number of ctors, and then the
	// actual list begins...
	int total = *(int *)constructor;
	constructor++ ;

	while(total--)
	{
		(*constructor)() ;
		constructor++ ;
	}
}

void ExecuteDestructors(void)
{
	void (**deconstructor)(void) = &dtorStart;

	int total = *(int *)deconstructor ;
	deconstructor++ ;

	while(total--)
	{
		(*deconstructor)() ;
		deconstructor++ ;
	}
}
So it seems that there is indeed a bug in the barebones tutorial. However, I wonder why nobody has noticed it yet... Calling some invalid address right at the beginning of any kernel code should almost inevitably lead to a triple fault.
Last edited by xenos on Mon Jan 31, 2011 4:25 am, edited 1 time in total.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Bug in C++ bare bones ctor/dtor examples?

Post by Combuster »

The "garbage" comes from a combination of crtbegin.o/crtend.o and your system's linker script, and is therefore only present if you add it there.

Barebones is not wrong.

Edit: The stock crosscompiler does not have this behaviour either.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: Bug in C++ bare bones ctor/dtor examples?

Post by xenos »

It took me quite a while how this "garbage" gets into the Trion kernel, which does not refer to crtbegin.o/crtend.o at all. I just had a look at the Trion kernel binary and I found the following contents (translated to asm code):

Code: Select all

ctorStart:
	dd 0x02
	dd 0x103bf0
	dd 0x105fa0
	dd 0x00
ctorEnd:
dtorStart:
	dd 0x01
	dd 0x105fc0
	dd 0x00
dtorEnd:
So indeed the ctor/dtor list are preceded by their lengths, and followed by a zery dword. But in this case it is not surprising because these values are generated in the linker script!

Code: Select all

SECTIONS {
  .text 0x00100000 :{
    textStart = .;
    *(.text)
    *(.text.*)
		*(.stub)
    *(.rodata*)
    *(.gnu.linkonce.t.*)
		*(.gnu.linkonce.r.*)
		*(.gcc_except_table)
		*(.eh_frame)
  }
  textEnd = .;

  .data :{
    ctorStart = .;
      LONG((ctorEnd - ctorStart) / 4 - 2)
      *(.ctors)
      LONG(0) ctorEnd = .;

    dtorStart = .;
      LONG((dtorEnd - dtorStart) / 4 - 2)
      *(.dtors)
      LONG(0) dtorEnd = .;

    *(.data*)
	 *(.gnu.linkonce.d.*)
  }
  dataEnd = .;

  .bss :{
    *(.common)
    *(.bss*)
	 *(.gnu.linkonce.b.*)
  }
  bssEnd = .;
}
I also had a look at crtbegin.o and crtend.o and both of them contain a single dword in the .ctors and .dtors sections - so I suppose that this is where the "garbage" comes from when these files are linked into the output binary. Another look at crtstuff.c and libgcc2.c from the gcc sources revealed that they actually rely on the presence of the "garbage" when they traverse the ctor/dtor lists.

However, as Combuster correctly explained, the "garbage" is not included by default by a plain cross compiler and (in general) not needed in an OS kernel, so the barebones example is correct.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
TylerH
Member
Member
Posts: 285
Joined: Tue Apr 13, 2010 8:00 pm
Contact:

Re: Bug in C++ bare bones ctor/dtor examples?

Post by TylerH »

Okay. That clears it up.

I wasn't concerned by the fact it wasn't there, I was just concerned that if it was there, it would screw stuff up, obviously. I didn't know this "feature" isn't enabled by default for cross compilers. But, since it's not there, there's no reason to care.

Thanks.
Post Reply