Page 1 of 1

Lost .ctors section from a static library

Posted: Mon Jul 18, 2011 11:26 pm
by torshie
I created a new staticly library libtest.a and linked it to my kernel. The static library will create some global objects. I found that the global objects from the static library are not constructed, but the global objects in the kernel are still constructed correctly. I also checked the elf files: the .ctors section of the kernel object file is 8 bytes, .ctors section of the static library(only one object file of the static library has a .ctors section) is 8 bytes. The .ctors section of the final executable is still 8 bytes. So I guess the .ctors section from the static library is lost somehow. The following is my linker script and the code used to initialize global objects. Do I missed anything in the linker script or my code used for construct global objects is wrong?

Code: Select all

typedef void (*Initializer)(void);

/* These two are defined in ld script */
extern "C" Initializer __wtn_ctors_begin__, __wtn_ctors_end__;

void initGlobalObjects() {
	for (Initializer* init = &__wtn_ctors_begin__; init < &__wtn_ctors_end__;
			++init) {
		(*init)();
	}
}

Code: Select all

OUTPUT_ARCH(i386:x86-64)
OUTPUT_FORMAT(elf64-x86-64)
ENTRY(__wtn_start)
PROVIDE(runAllTestCase = 0);
GROUP(-ltest -lcxxrt -lcrt-x64 -lunwind)

SECTIONS {
	. = 0xFFFFFFFF80000000 + 0x100000 + 0x100000;

	__wtn_stack_bottom__ = .;

	.init : ALIGN(16) {
		*(.init)
	}

	.text : ALIGN(16) {
		*(.text .text.*)
	}

	. = ALIGN(4096);

	.rodata : {
		*(.rodata .rodata.*)
	}

	.eh_frame_hdr : ALIGN(16) {
		*(.eh_frame_hdr)
	}
	.eh_frame : ONLY_IF_RO {
		__wtn_eh_frame_start__ = .;
		*(.eh_frame)
	}
	.gcc_except_table : ONLY_IF_RO {
		*(.gcc_except_table .gcc_except_table.*)
	}

	.ctors : ALIGN(16) {
		__wtn_ctors_begin__ = .;
		KEEP(*(SORT(.ctors.*)))
		KEEP(*(.ctors))
		__wtn_ctors_end__ = .;
	}

	.dtors : ALIGN(16) {
		KEEP(*(SORT(.dtors.*)))
		KEEP(*(.dtors))
	}

	.note : ALIGN(16) {
		*(.note.gnu.build-id)
	}

	. = ALIGN(4096);

	.eh_frame : ONLY_IF_RW {
		*(.eh_frame)
	}
	.gcc_except_table : ONLY_IF_RW {
		*(.gcc_except_table .gcc_except_table.*)
	}

	.data : ALIGN(16) {
		*(.data .data.*);
	}

	.bss : ALIGN(16) {
		*(.bss .bss.*)
		*(COMMON)
	}

	. = ALIGN(4096);
	__wtn_image_end__ = .;

	/DISCARD/ : {
		*(.comment)
	}
}
Thanks
-torshie

Re: Lost .ctors section from a static library

Posted: Tue Jul 19, 2011 1:06 am
by Combuster
If your code does not include portions of static libraries, it usually means they are not referenced: For instance, if you don't use cout/cin/cerr, there's no need at all to create those objects at startup, and therefore their ctors/dtors are not needed.

Re: Lost .ctors section from a static library

Posted: Tue Jul 19, 2011 2:22 am
by torshie
These global objects are NOT referenced directly. But these objects have non-trivial constructors, in the constructors, one global variable will be changed, and the global variable will be referenced.
I also tried partial library(ld -r), when a partial library instead of a static library is created, the executable runs as expected.

Re: Lost .ctors section from a static library

Posted: Tue Jul 19, 2011 3:47 am
by Combuster
But that still means nothing depends on the object file with the constructors. You apparently require KDE to run a mount command just because KDE depends on it :wink:

Re: Lost .ctors section from a static library

Posted: Tue Jul 19, 2011 3:49 am
by Owen
Static libraries are designed so that the linker only pulls out the objects which contain symbols referenced by objects already linked. You can think of the process traditional LD uses as follows:
  1. Create an empty internal representation of an object
  2. foreach input in inputs {
  3. Look at an imput file (whether supplied as a path or a -l parameter)
  4. If its an object, merge it with the ones already processed
  5. If its a static library, look up each undefined symbol against the library symbol table. If a symbol is found, pull in that object. This process is repeated for any undefined symbols introduced by the object being pulled in
  6. Move to the next input
  7. }
A more modern linker, like ObjectTools' OT::Linker class (ObjectTools being the set of libraries and tools I'm working on; sorry, not yet released) may do this process in a more advanced and more friendly format (For example, I link all passed object files together and then do multiple passes over the libraries until either a symbol is declared undefined, which raises an error, or the symbol is successfully linked) when not operating in a strict compatibility mode. However, the core of it is still the same.

ld -r just merges the passed objects into a single relocatable object file. You can think of this as being the internal form that the object takes before an image writer proceeds to write it out to a file. This is certainly how ObjectTools does things, though this all happens with the internal representation. It is not a "partial library"; it is just a way of merging relocatable objects.