[C++] Problem with in-class static field

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.
Post Reply
uzytkownik
Posts: 14
Joined: Sat Nov 15, 2008 3:39 pm

[C++] Problem with in-class static field

Post by uzytkownik »

I have an in-class static fields. The problem is that I get undefined references. Probably I missing something in linker script.

Code: Select all

OUTPUT_FORMAT("elf32-i386")
ENTRY(start)
phys = 0x00100000;
virt = 0xC0000000;
SECTIONS
{
	. = phys;
	.setup :
	{
		*(.setup)
	}
	. += virt;
	. = ALIGN(0x1000);
	.text : AT(ADDR(.text) - virt)
	{
		code = .;
		phys_code = . - virt;
		*(.text)
	}
	. = ALIGN(0x1000);
	.data : AT(ADDR(.data) - virt)
	{
		data = .;
		phys_data = . - virt;
		*(.data)
	}
	. = ALIGN(0x1000);
	.bss : AT(ADDR(.bss) - virt)
	{
		bss = .;
		phys_bss = . - virt;
		*(COMMON)
		*(.bss)
	}
	. = ALIGN(0x1000);
	end = .;
	phys_end = . - virt;
	phys = phys;
	virt = virt;
}
Error codes:

Code: Select all

g++ -Wl,-T arch/i386/linker.ld -Wl,--cref -Wl,-Map -Wl,nios.map -o nios arch/i386/multiboot.o arch/i386/start.o arch/i386/kernel/memory.o -nostartfiles
arch/i386/kernel/memory.o: In function `real_page_allocator<8u>::allocate()':
memory.cc:(.text._ZN19real_page_allocatorILj8EE8allocateEv[real_page_allocator<8u>::allocate()]+0xc): undefined reference to `real_page_allocator<8u>::free_pages'
memory.cc:(.text._ZN19real_page_allocatorILj8EE8allocateEv[real_page_allocator<8u>::allocate()]+0x36): undefined reference to `real_page_allocator<8u>::feed_lock'
memory.cc:(.text._ZN19real_page_allocatorILj8EE8allocateEv[real_page_allocator<8u>::allocate()]+0x5e): undefined reference to `real_page_allocator<8u>::feed_lock'
arch/i386/kernel/memory.o: In function `real_page_allocator<8u>::feed(void*, unsigned int)':
memory.cc:(.text._ZN19real_page_allocatorILj8EE4feedEPvj[real_page_allocator<8u>::feed(void*, unsigned int)]+0x88): undefined reference to `real_page_allocator<8u>::free_pages'
collect2: ld returned 1 exit status
make: *** [all] Error 1
C++ file:

Code: Select all

#include "kiapi/kernel/memory.hh"
#include <new>
#include <map>
#include <cstdatomic>
#include <inttypes.h>

template<size_t size>
class real_page_allocator;

template <typename T>
class base_atomic_stack
{
public:
  struct bucket
  {
    bucket *next;
    T value;
  };
private:
  std::atomic<bucket *> head;
public:
  bucket *pop()
  {
    bucket *old_head = head.load();
    bucket *next;
    do
      {
	if (__builtin_expect(old_head == NULL, false))
	  return NULL;
	next = old_head->next;
      }
    while (head.compare_exchange_strong(old_head, next));
    return old_head;
  }
  void push(bucket *b)
  {
    do
      {
	b->next = head.load();
      }
    while(head.compare_exchange_strong(b->next, b));
  }
  void feed(bucket *first, bucket *last)
  {
    do
      {
	last->next = head.load();
      }
    while(head.compare_exchange_strong(last->next, first));
  }
};

template<size_t size>
class real_page_allocator
{
  struct dummy {};
  static base_atomic_stack<dummy> free_pages;
  typedef typename base_atomic_stack<dummy>::bucket bucket;
  static std::atomic_flag feed_lock;
  static void feed(void *ptr, size_t length)
  {
    char *buckets = reinterpret_cast<char *>(ptr);
    size_t s = std::min(size, sizeof(bucket));
    bucket *next = NULL;
    for(size_t i = 0; i < length - s + 1; i += s)
      {
	bucket *b = reinterpret_cast<bucket *>(&buckets[i]);
	b->next = next;
	next = b;
      }
    free_pages.feed(next, reinterpret_cast<bucket *>(buckets));
  }
  static void feed()
  {
    typedef kiapi::kernel::memory::memory memory;
    typedef kiapi::kernel::memory::virtual_memory virtual_memory;
    typedef kiapi::kernel::memory::hardware_address hardware_address;
    memory &main = memory::get_main();
    hardware_address address = main.allocate();
    size_t page_size = main.page_size();
    virtual_memory &kvmem = virtual_memory::get_kernel();
    void *ptr = kvmem.reserve(page_size);
    kvmem.map(ptr, address, page_size);
    feed(ptr, page_size);
  }
public:
  static void *allocate()
  {
    do
      {
	bucket *b = free_pages.pop();
	if(__builtin_expect(b != NULL, true))
	  return b;
	if(__builtin_expect(!feed_lock.test_and_set(), true))
	  {
	    feed();
	    feed_lock.clear();
	  }
      }
    while(true);
  }
  static void deallocate(void *__p)
  {
    free_pages.push(reinterpret_cast<bucket *>(__p));
  }
};

template<typename T>
class page_allocator
{
  typedef real_page_allocator<sizeof(T)> rpage_allocator;
public:
  typedef size_t    size_type;
  typedef ptrdiff_t difference_type;
  typedef T*        pointer;
  typedef const T*  const_pointer;
  typedef T&        reference;
  typedef const T&  const_reference;
  typedef T         value_type;
  
  template<typename T1>
  struct rebind
  {
    typedef page_allocator<T1> other;
  };

  page_allocator() throw() { }
  page_allocator(const page_allocator &) throw() { }
  template<typename T1>
  page_allocator(const page_allocator<T1>) throw() { }

  pointer address(reference __x) const { return &__x; }
  const_pointer address(const_reference __x) const { return &__x; }

  pointer allocate(size_type __n, const void * = 0)
  {
    if (__builtin_expect(__n > 1, false))
      {
	std::__throw_bad_alloc();
      }
    if (__builtin_expect(__n == 1, true))
      {
	return reinterpret_cast<pointer>(rpage_allocator::allocate());
      }
    return NULL;
  }

  void deallocate(pointer __p, size_type)
  {
    rpage_allocator::deallocate(__p);
  }

  size_type max_size() const throw()
  {
    return 1;
  }

  void construct(pointer __p, const T &__val)
  {
    ::new((void *)__p) T(__val);
  }

  void destroy(pointer __p)
  {
    __p->~T();
  }

  inline bool operator==(const page_allocator &)
  {
    return true;
  }

  inline bool operator!=(const page_allocator &)
  {
    return false;
  }
};

template<typename T>
class atomic_stack
{
  base_atomic_stack<T> stack;
  typedef typename base_atomic_stack<T>::bucket bucket;
  page_allocator<bucket> bucket_allocator;
public:
  bool pop(T &__p)
  {
    bucket *b = stack.pop();
    if(__builtin_expect(b == NULL, false))
      {
	return false;
      }
    else
      {
	__p = b->value;
	bucket_allocator.deallocate(b, 1);
	return true;
      }
  }
  void push(T &__p)
  {
    bucket *b = bucket_allocator.allocate(1);
    b->value = __p;
  }
};

template<typename T>
class atomic_stack<T *>
{
  base_atomic_stack<T *> stack;
  typedef typename base_atomic_stack<T *>::bucket bucket;
  page_allocator<bucket> bucket_allocator;
public:
  bool pop(T *&__p)
  {
    bucket *b = stack.pop();
    if (__builtin_expect(b == NULL, false))
      {
	__p = NULL;
	return false;
      }
    else
      {
	__p = b->value;
	bucket_allocator.deallocate(b);
	return true;
      }
  }
  T *pop()
  {
    bucket *b = stack.pop();
    T *t = b->value;
    bucket_allocator.deallocate(b);
    return t;
  }
  void push(T *__p)
  {
    bucket *b = bucket_allocator.allocate(1);
    b->value = __p;
  }
};

class main_memory : kiapi::kernel::memory::memory
{
  typedef kiapi::kernel::memory::hardware_address hardware_address;
  atomic_stack<hardware_address> stack;
public:
  size_t page_size()
  {
    return 4096;
  }
  hardware_address allocate()
  {
    hardware_address address;
    stack.pop(address);
    return address;
  }
  hardware_address acquire(hardware_address address)
  {
    // Not implemented yet
    return hardware_address();
  }
  void release(hardware_address address)
  {
    stack.push(address);
  }
};

kiapi::kernel::memory::memory &
kiapi::kernel::memory::memory::get_main()
{
  static char main[sizeof(main_memory)];
  return reinterpret_cast<kiapi::kernel::memory::memory &>(main);
}

class dma_memory : kiapi::kernel::memory::memory
{
  typedef kiapi::kernel::memory::hardware_address hardware_address;
  static const size_t _page_size = 128*1024;
  // On most system it should be 96. Linear search should be sufficient
  static const size_t pages = (DMA_END - DMA_START)/_page_size;
  std::atomic<unsigned char> allocated[pages];
  std::atomic<unsigned char> &page (hardware_address address)
  {
    return allocated[(address.ptr - DMA_START)/_page_size];
  }
public:
  size_t page_size()
  {
    return _page_size;
  }
  hardware_address allocate()
  {
    for (int i = 0; i < pages; i++)
      {
	unsigned char free = 0, occupied = 1;
	if (allocated[i].compare_exchange_strong(free, occupied))
	  {
	    return (int)(DMA_START+_page_size*i);
	  }
      }
    return hardware_address();
  }
  hardware_address acquire(hardware_address address)
  {
    page(address) += 1;
    return address;
  }
  void release(hardware_address address)
  {
    page(address) -= 1;
  }
};

kiapi::kernel::memory::memory &
kiapi::kernel::memory::memory::get_dma()
{
  static char dma[sizeof(dma_memory)];
  return reinterpret_cast<kiapi::kernel::memory::memory &>(dma);
}

// kiapi::kernel::memory::virtual_memory

typedef kiapi::kernel::memory::virtual_memory virtual_memory;

virtual_memory::virtual_memory() {}
virtual_memory::virtual_memory(const virtual_memory &) {}
virtual_memory::virtual_memory(virtual_memory::vm *vm)
{
  this->priv = vm;
}

size_t
virtual_memory::page_size() const
{
  return 4096;
}

void *
virtual_memory::reserve(size_t)
{
  return NULL;
}

void *
virtual_memory::reserve(void *, size_t)
{
  return NULL;
}

void
virtual_memory::map(void *, hardware_address, size_t)
{
}

void
virtual_memory::unmap(void *, size_t)
{
}

kiapi::kernel::memory::hardware_address
virtual_memory::lookup(void *) const
{
  return kiapi::kernel::memory::hardware_address();
}

virtual_memory &
virtual_memory::get_kernel()
{
  static char kernel[sizeof(virtual_memory)];
  return reinterpret_cast<virtual_memory &>(kernel);
}

bool kiapi::kernel::memory::init(multiboot_info *info)
{
  atomic_stack<multiboot_info *> a;
  a.push(info);
}
PS. Please note that I'm using partially C++0x - for atomic operations
uzytkownik
Posts: 14
Joined: Sat Nov 15, 2008 3:39 pm

Re: [C++] Problem with in-class static field

Post by uzytkownik »

Yes - you are right (except the definition was in source code).
Post Reply