Page 1 of 1
Bug in C++ bare bones ctor/dtor examples?
Posted: Sun Jan 30, 2011 9:06 pm
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?
Re: Bug in C++ bare bones ctor/dtor examples?
Posted: Mon Jan 31, 2011 12:40 am
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.
Re: Bug in C++ bare bones ctor/dtor examples?
Posted: Mon Jan 31, 2011 3:04 am
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.
Re: Bug in C++ bare bones ctor/dtor examples?
Posted: Mon Jan 31, 2011 3:27 am
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.
Re: Bug in C++ bare bones ctor/dtor examples?
Posted: Mon Jan 31, 2011 5:23 am
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.
Re: Bug in C++ bare bones ctor/dtor examples?
Posted: Mon Jan 31, 2011 3:52 pm
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.