[C++] Problem with in-class static field
Posted: Sat Apr 25, 2009 4:09 pm
I have an in-class static fields. The problem is that I get undefined references. Probably I missing something in linker script.
Error codes:
C++ file:
PS. Please note that I'm using partially C++0x - for atomic operations
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;
}
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
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);
}