Linking fails with templates? [SOLVED]

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.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Linking fails with templates? [SOLVED]

Post by pcmattman »

I'm testing out my knowledge of templates (and making sure I know how GCC likes them, I learnt on MSVC++ 6). I've written the following, really basic, class:

Code: Select all

template< typename T >
class Accumulator
{
	public:
		T Value();
		T operator = ( T val );
	private:
		T m_val;
};
This compiles fine (the code is implemented, I'm just not going to show it because it's simple enough, Value() just returns m_val, the '=' operator sets m_val and then returns it.

However, once it hits the linker, all hell breaks loose:

Code: Select all

c:/djgpp/bin/ld-elf.exe: kernel.o: Unrecognized storage class 127 for /4 symbol `__ZN11AccumulatorIj
EaSEj'
c:/djgpp/bin/ld-elf.exe: kernel.o: Unrecognized storage class 127 for /44 symbol `__ZN11AccumulatorI
jE5ValueEv'
The code which causes this:

Code: Select all

Accumulator<int> acc;
acc = 0;
int val = acc.Value();
This is the way I learnt to use templates. GCC doesn't like it. Any ideas?

Edit: solution is on next page...
Last edited by pcmattman on Sat Jun 02, 2007 10:40 pm, edited 1 time in total.
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post by os64dev »

with the implementation i tried

Code: Select all

template< typename T > 
T Accumulator<T>::Value(){
    return(m_val);
}

template< typename T > 
T Accumulator<T>::operator = (T val){
    return(m_val = val);
}
everything works fine under gcc 4.1.2 cross-compiler.
Author of COBOS
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

I can't get it...

GCC version:

Code: Select all

Using built-in specs.
Target: djgpp
Configured with: /gnu/gcc-4.10/configure djgpp --prefix=/dev/env/DJDIR --disable-nls --disable-werro
r --enable-languages=c,c++,fortran,objc,obj-c++,ada
Thread model: single
gcc version 4.1.0
Edit: It seems to be in the class instance initialization, not in the actual implementation. Accumulator<int> is a cause of the error (presumably because of the constructor?)... As is the = operator and Value().

Edit 2: No member functions work at all, but initialization does:

Code: Select all

Accumulator<int> acc;
acc.test(); // commment this out, it works perfectly, leave uncommented, doesn't work
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

What is the exact command line(s) you're invocating the compiler / linker with?

What does your linker script look like?
Every good solution is obvious once you've found it.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

Command lines:

Code: Select all

gcc -I "C:\osdev\cppkern\include" -c *.cc */*.cc -nostdlib -fno-builtin -fno-rtti -fno-exceptions

ld-elf -T linker.ld -o kernel.bin loader.obj *.o
Linker script:

Code: Select all

ENTRY (_loader) 

SECTIONS 
{ 
   . = 0x00100000; 

   .text : 
   { 
      *(.text) 
   } 

   .rodata ALIGN (0x1000) : 
   { 
      *(.rodata) 
   } 

   .data ALIGN (0x1000) : 
   { 
      start_ctors = .; 
      *(.ctor*) 
      end_ctors = .; 
      start_dtors = .; 
      *(.dtor*) 
      end_dtors = .; 
      *(.data) 
   } 

   .bss : 
   { 
      _sbss = .; 
      *(COMMON) 
      *(.bss) 
      _ebss = .; 
   } 
}
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

Try adding this behind *(.text)
*(.text.*)

Virtual classes and templates seem to go into sections like .text._ZN6BufferI11FILE_INFO_SLj16EE6CreateEjjj
User avatar
mystran
Member
Member
Posts: 670
Joined: Thu Mar 08, 2007 11:08 am

Post by mystran »

What's the version of binutils? The error message suggests to me that GCC is requesting something not supported by your LD, so make sure you have a compatible (=reasonably new) version of binutils as well.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post by os64dev »

Does gcc immediatly recognises C++ or do you need to use gcc -x c++ or g++
Author of COBOS
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

Indeed, you have to use g++ to invoke the C++ compiler, not gcc. You're trying to compile C++ code with a C toolchain.
Every good solution is obvious once you've found it.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

It recognizes *.cc as a c++ file extension. I'm using classes already (and they work as long as they aren't templates)...
User avatar
mystran
Member
Member
Posts: 670
Joined: Thu Mar 08, 2007 11:08 am

Post by mystran »

Gcc should recognize C++ from .cc or .cpp or .cxx or (on case-sensitive filesystems) .C extension. The error message sounds like your linker doesn't support common symbols, or some similar issue, so please, check that you have reasonably up-to-date binutils.

Gcc emits code that results from template-expansion as common, such that when you link several object files, if they contain the same expansions, you'll only get one copy in the resulting binary. This requires support from linker.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Post by Candy »

pcmattman wrote:It recognizes *.cc as a c++ file extension. I'm using classes already (and they work as long as they aren't templates)...
Could you try linking with g++ instead of ld? g++ does a number of things slightly different in invoking ld than gcc does, it might be one of those things. Another thing could be that your binutils chain doesn't match your gcc chain, but that's fairly unlikely.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

Ah... I let G++ run the linker for me, and I have no problems. Apart from the fact that my 'loader.o' object isn't linked in - this is really important because it handles startup (setting up the stack, GDT stuff etc...). How can I tell G++ to tell the linker to link in an object first?
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Post by Candy »

pcmattman wrote:Ah... I let G++ run the linker for me, and I have no problems. Apart from the fact that my 'loader.o' object isn't linked in - this is really important because it handles startup (setting up the stack, GDT stuff etc...). How can I tell G++ to tell the linker to link in an object first?
To be quite honest, you don't. You tell it which objects it can use and which function should be the first, and for all function groups how to place them etc., but you can't force it to locate stuff somewhere. The concept is that you tell it which function should go first (--entry) and that it orders stuff so that the executable format understands that your function is the entry point (as first byte of the file, 257th, entry point pointer there etc.) and that all other required functions are included. It should not skip any files unless they're really not used.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

Actually there's another reason why that loader has to go first - it holds the multiboot header...
Post Reply