From b4f1ab54b36f7dc273b9a80081c019f7d6618715 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Thu, 9 Sep 2010 12:04:57 -0500 Subject: Support modules. --- config.mk | 2 +- obj/modules/example/.gitignore | 0 src/bld/linker.C | 358 +++++++++++++++++++++++++++++++++++++++-- src/bld/makefile | 2 +- src/include/sys/vfs.h | 18 +++ src/kernel/pagemgr.C | 6 +- src/makefile | 2 +- src/module.ld | 35 ++++ src/sys/init/init_main.C | 6 +- src/sys/vfs/vfs_main.C | 23 +++ src/usr/example/example.C | 28 ++++ src/usr/example/makefile | 16 ++ src/usr/makefile | 9 ++ 13 files changed, 488 insertions(+), 17 deletions(-) create mode 100644 obj/modules/example/.gitignore create mode 100644 src/module.ld create mode 100644 src/usr/example/example.C create mode 100644 src/usr/example/makefile create mode 100644 src/usr/makefile diff --git a/config.mk b/config.mk index 5d2b2c028..14aefa449 100644 --- a/config.mk +++ b/config.mk @@ -21,7 +21,7 @@ ${OBJDIR}/%.o : %.c ${OBJDIR}/%.o : %.S ${CC} -c ${ASMFLAGS} $< -o $@ -Wa,-I${INCDIR} -${OBJDIR}/%.so : ${OBJECTS} ${ROOTPATH}/src/module.ld +${IMGDIR}/%.so : ${OBJECTS} ${ROOTPATH}/src/module.ld ${LD} -shared -z now --gc-sections ${LDFLAGS} $< \ -T ${ROOTPATH}/src/module.ld -o $@ diff --git a/obj/modules/example/.gitignore b/obj/modules/example/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/src/bld/linker.C b/src/bld/linker.C index 59cbf6416..fda2059d4 100644 --- a/src/bld/linker.C +++ b/src/bld/linker.C @@ -3,34 +3,74 @@ #include #include #include +#include #include #include #include #include +#include +#include + +#include using std::cout; using std::endl; using std::string; using std::vector; +using std::map; +using std::for_each; +using std::mem_fun_ref; +using std::bind1st; + +struct Symbol +{ + string name; + uint8_t type; + uint64_t address; + uint64_t addend; + + enum SymbolType + { + LOCAL = 0x01, + GLOBAL = 0x02, + + UNRESOLVED = 0x04, + + FUNCTION = 0x08, + VARIABLE = 0x10, + + RELATIVE = 0x20, + }; +}; struct Section { string name; size_t vma_offset; size_t size; - + bfd_byte* data; }; struct Object { public: + string name; bfd* image; Section text; Section data; - + map symbols; + vector relocs; + long offset; + bool read_object(char* file); bool write_object(FILE* file); + bool read_relocation(); + bool perform_local_relocations(FILE* file); + bool perform_global_relocations(FILE* file); + + uint64_t find_init_symbol(); + uint64_t find_start_symbol(); }; vector objects; @@ -59,16 +99,79 @@ int main(int argc, char** argv) Object o; if (o.read_object(argv[files])) { + o.read_relocation(); objects.push_back(o); + cout << endl; } } - for (vector::iterator i = objects.begin(); + for_each(objects.begin(), objects.end(), + bind2nd(mem_fun_ref(&Object::write_object), output)); + uint64_t last_address = ftell(output); + + cout << "Local relocations..." << endl; + for_each(objects.begin(), objects.end(), + bind2nd(mem_fun_ref(&Object::perform_local_relocations), output)); + cout << endl; + + cout << "Global relocations..." << endl; + for_each(objects.begin(), objects.end(), + bind2nd(mem_fun_ref(&Object::perform_global_relocations), output)); + cout << endl; + + // Create module table. + uint64_t module_table_address = + objects[0].symbols[VFS_TOSTRING(VFS_MODULES)].address + + objects[0].offset + objects[0].data.vma_offset; + + fseek(output, module_table_address, SEEK_SET); + + if ((objects.size()-1) > VFS_MODULE_MAX) + { + cout << "Error: Too many modules." << endl; + return -1; + } + + cout << "Updating module table... " << endl; + for (vector::iterator i = ++objects.begin(); i != objects.end(); ++i) { - i->write_object(output); + string object_name = i->name; + object_name.erase(0, object_name.find_last_of("/")+1); + + char obj_name[VFS_MODULE_NAME_MAX]; + memset(obj_name, '\0', VFS_MODULE_NAME_MAX); + strncpy(obj_name, object_name.c_str(), VFS_MODULE_NAME_MAX-1); + fwrite(obj_name, VFS_MODULE_NAME_MAX, 1, output); + + uint64_t init_symbol = i->find_init_symbol(); + uint64_t start_symbol = i->find_start_symbol(); + + char data[sizeof(uint64_t)]; + + bfd_putb64(init_symbol, data); + fwrite(data, sizeof(uint64_t), 1, output); + bfd_putb64(start_symbol, data); + fwrite(data, sizeof(uint64_t), 1, output); + + cout << "\tAdded module " << object_name << " with init at " + << std::hex << init_symbol << " and start at " + << start_symbol << endl; } + + cout << "Updating last address..." << std::hex; + uint64_t last_address_entry_address = + objects[0].symbols[VFS_TOSTRING(VFS_LAST_ADDRESS)].address + + objects[0].offset + objects[0].data.vma_offset; + + fseek(output, last_address_entry_address, SEEK_SET); + char last_addr_data[sizeof(uint64_t)]; + bfd_putb64(last_address, last_addr_data); + fwrite(last_addr_data, sizeof(uint64_t), 1, output); + + cout << last_address << " to " << last_address_entry_address << endl; + return 0; } @@ -81,7 +184,8 @@ bool Object::read_object(char* file) cout << "Unsupported file format: " << file << endl; return false; } - + + name = file; cout << "File " << file << endl; // Read sections. @@ -115,8 +219,6 @@ bool Object::read_object(char* file) image_section = image_section->next; } - cout << endl; - return true; } @@ -133,7 +235,7 @@ bool Object::write_object(FILE* file) { // Start outputing object at page boundary. advance_to_page_align(file); - long start_pos = ftell(file); + offset = ftell(file); // Output TEXT section. fseek(file, text.vma_offset, SEEK_CUR); @@ -145,7 +247,7 @@ bool Object::write_object(FILE* file) } // Output DATA section. - fseek(file, start_pos + data.vma_offset, SEEK_SET); + fseek(file, offset + data.vma_offset, SEEK_SET); if (data.size != fwrite(data.data, 1, data.size, file)) { int error = errno; @@ -153,3 +255,241 @@ bool Object::write_object(FILE* file) cout << strerror(error) << endl; } } + +bool Object::read_relocation() +{ + asymbol** syms = NULL; + long symbols = 0; + arelent** loc = NULL; + long locs = 0; + + // Read symbol tables. + { + long symbol_size = bfd_get_dynamic_symtab_upper_bound(image); + if (0 < symbol_size) + { + syms = (asymbol**) malloc(symbol_size); + symbols = bfd_canonicalize_dynamic_symtab(image, syms); + } + } + if (0 >= symbols) + { + long symbol_size = bfd_get_symtab_upper_bound(image); + if (0 < symbol_size) + { + syms = (asymbol**) malloc(symbol_size); + symbols = bfd_canonicalize_symtab(image, syms); + } + } + if (0 >= symbols) + { + cout << "Couldn't find symbol table." << endl; + return false; + } + cout << "Symbols: " << std::dec << symbols << endl; + for (int i = 0; i < symbols; i++) + { + Symbol s; + s.name = syms[i]->name; + s.address = syms[i]->value; + s.type = 0; + + cout << "\tSymbol: " << syms[i]->name << endl; + cout << "\t\tAddress: " << std::hex << syms[i]->value << endl; + + // Determine symbol types. + if (syms[i]->flags & BSF_GLOBAL) + { + s.type |= Symbol::GLOBAL; + cout << "\t\tGLOBAL" << endl; + } + else if (syms[i]->flags & (BSF_LOCAL | BSF_WEAK)) + { + s.type |= Symbol::LOCAL; + cout << "\t\tLOCAL" << endl; + } + else + { + s.type |= Symbol::UNRESOLVED; + cout << "\t\tUNDEFINED " << std::hex << syms[i]->flags << endl; + } + + if (syms[i]->flags & BSF_FUNCTION) + { + s.type |= Symbol::FUNCTION; + cout << "\t\tFUNCTION" << endl; + } + else if (!(s.type & Symbol::UNRESOLVED)) + { + s.type |= Symbol::VARIABLE; + cout << "\t\tVARIABLE" << endl; + } + + // Add symbol to table. + if (!(s.type & Symbol::UNRESOLVED)) + this->symbols[s.name] = s; + } + + // Read relocations. + { + long loc_size = bfd_get_dynamic_reloc_upper_bound(image); + if (0 < loc_size) + { + loc = (arelent**) malloc(loc_size); + memset(loc, '\0', loc_size); + locs = bfd_canonicalize_dynamic_reloc(image, loc, syms); + } + } + if (0 >= locs) + { + goto cleanup; + } + + cout << "Relocs: " << std::dec << locs << endl; + for (int i = 0; i < locs; i++) + { + Symbol s; + + s.name = loc[i]->sym_ptr_ptr[0]->name; + s.address = loc[i]->address; + s.addend = loc[i]->addend; + if ((s.name == BFD_ABS_SECTION_NAME) || + (this->symbols.find(s.name) != this->symbols.end())) + { + s.type = Symbol::RELATIVE; + } + else + { + s.type = Symbol::UNRESOLVED; + } + this->relocs.push_back(s); + + cout << "\tSymbol: " << loc[i]->sym_ptr_ptr[0]->name; + cout << "\tAddress: " << std::hex << loc[i]->address << ", " + << loc[i]->addend << endl; + } + +cleanup: + if (NULL != loc) + free(loc); + if (NULL != syms) + free(syms); + + return true; +} + +bool Object::perform_local_relocations(FILE* file) +{ + cout << "File " << name << endl; + + for(vector::iterator i = relocs.begin(); + i != relocs.end(); + ++i) + { + if (i->type & Symbol::UNRESOLVED) + continue; + + cout << "\tSymbol: " << i->name << endl; + + uint64_t relocation = i->addend + offset; + uint64_t address = 0; + char data[sizeof(uint64_t)]; + + fseek(file, offset + i->address, SEEK_SET); + fread(data, sizeof(uint64_t), 1, file); + + address = bfd_getb64(data); + if (address != i->addend) + { + cout << "Expected " << i->addend << " found " << address << endl; + continue; + } + + address = relocation; + bfd_putb64(address, data); + + fseek(file, offset + i->address, SEEK_SET); + fwrite(data, sizeof(uint64_t), 1, file); + + cout << "\tRelocated " << i->addend << " to " + << relocation << endl; + } +} + +bool Object::perform_global_relocations(FILE* file) +{ + cout << "File " << name << endl; + + for(vector::iterator i = relocs.begin(); + i != relocs.end(); + ++i) + { + if (!(i->type & Symbol::UNRESOLVED)) + continue; + + cout << "\tSymbol: " << i->name << endl; + + char data[sizeof(uint64_t)*3]; + + for(vector::iterator j = objects.begin(); + j != objects.end(); + ++j) + { + if (j->symbols.find(i->name) != j->symbols.end()) + { + Symbol s = j->symbols[i->name]; + uint64_t symbol_addr = + j->offset + s.address + j->data.vma_offset; + + if (s.type & Symbol::UNRESOLVED) + continue; + if (s.type & Symbol::LOCAL) + continue; + if (!(s.type & Symbol::GLOBAL)) + continue; + + if (s.type & Symbol::FUNCTION) + { + fseek(file, symbol_addr, SEEK_SET); + fread(data, sizeof(uint64_t), 3, file); + + fseek(file, offset + i->address, SEEK_SET); + fwrite(data, sizeof(uint64_t), 3, file); + + cout << "\tCopied relocation from " << std::hex + << symbol_addr << " to " + << offset + i->address << "." << endl; + } + else + { + bfd_putb64(symbol_addr, data); + fseek(file, offset + i->address, SEEK_SET); + fwrite(data, sizeof(uint64_t), 1, file); + + cout << "\tRelocated from " << std::hex + << symbol_addr << " to " + << offset + i->address << "." << endl; + } + break; + } + } + } +} + +uint64_t Object::find_init_symbol() +{ + if (symbols.find(VFS_TOSTRING(VFS_SYMBOL_INIT)) == symbols.end()) + return 0; + + return symbols[VFS_TOSTRING(VFS_SYMBOL_INIT)].address + + offset + data.vma_offset; +} + +uint64_t Object::find_start_symbol() +{ + if (symbols.find(VFS_TOSTRING(VFS_SYMBOL_START)) == symbols.end()) + return 0; + + return symbols[VFS_TOSTRING(VFS_SYMBOL_START)].address + + offset + data.vma_offset; +} diff --git a/src/bld/makefile b/src/bld/makefile index 37fd2e4b1..d80e2b533 100644 --- a/src/bld/makefile +++ b/src/bld/makefile @@ -1,5 +1,5 @@ linker: linker.C - g++ -O3 linker.C -o linker -lbfd + g++ -O3 -g linker.C -o linker -lbfd -I../include/sys all: linker diff --git a/src/include/sys/vfs.h b/src/include/sys/vfs.h index 579b9ba34..e596030fe 100644 --- a/src/include/sys/vfs.h +++ b/src/include/sys/vfs.h @@ -3,6 +3,13 @@ #include +#define VFS_MODULE_MAX 128 +#define VFS_MODULE_NAME_MAX 64 +#define VFS_SYMBOL_INIT _init +#define VFS_SYMBOL_START _start +#define VFS_STRINGIFY(X) #X +#define VFS_TOSTRING(X) VFS_STRINGIFY(X) + #ifdef __cplusplus extern "C" { @@ -19,6 +26,17 @@ enum VfsMessages VFS_MSG_RESOLVE_MSGQ, }; +struct VfsSystemModule +{ + const char module[VFS_MODULE_NAME_MAX]; + void (*init)(void*); + void (*start)(void*); +}; + +extern VfsSystemModule VFS_MODULES[VFS_MODULE_MAX]; +extern uint64_t VFS_LAST_ADDRESS; + + #ifdef __cplusplus } #endif diff --git a/src/kernel/pagemgr.C b/src/kernel/pagemgr.C index 022b642b0..2a92df206 100644 --- a/src/kernel/pagemgr.C +++ b/src/kernel/pagemgr.C @@ -1,6 +1,7 @@ #include #include #include +#include void PageManager::init() { @@ -21,11 +22,8 @@ void PageManager::freePage(void* p, size_t n) PageManager::PageManager() { - // NOTE: This will need to change once we support loading modules. - // Determine first page of un-allocated memory. - extern void* end_load_address; - uint64_t addr = (uint64_t)&end_load_address; + uint64_t addr = (uint64_t) VFS_LAST_ADDRESS; if (0 != (addr % PAGESIZE)) addr = (addr - (addr % PAGESIZE)) + PAGESIZE; diff --git a/src/makefile b/src/makefile index 6045de28b..4117b7946 100644 --- a/src/makefile +++ b/src/makefile @@ -2,7 +2,7 @@ ROOTPATH = .. IMGDIR = ${ROOTPATH}/img OBJDIR = ${ROOTPATH}/obj/hbicore -SUBDIRS = kernel.d lib.d libc++.d sys.d bld.d +SUBDIRS = kernel.d lib.d libc++.d sys.d usr.d bld.d IMAGES += ${IMGDIR}/hbicore.elf IMAGES += ${IMGDIR}/hbicore.bin diff --git a/src/module.ld b/src/module.ld new file mode 100644 index 000000000..f94f97218 --- /dev/null +++ b/src/module.ld @@ -0,0 +1,35 @@ +SECTIONS +{ + .text : { + *(.text) + *(.text._*) + *(.rodata) + *(.rodata.*) + *(.glink) + + . = ALIGN(0x8); + ctor_start_address = .; + *(.ctors) + ctor_end_address = .; + } + + .data ALIGN(0x1000): { + *(.data) + *(.data.*) + *(.branch_lt) + *(.toc) + *(.opd) + *(.got) + *(.plt) + *(.bss) + *(.bss.*) + } + + .rela : { + *(.rela.*) + } + + /DISCARD/ : { + *(.dtors) + } +} diff --git a/src/sys/init/init_main.C b/src/sys/init/init_main.C index 4be986ba7..72bfc64a8 100644 --- a/src/sys/init/init_main.C +++ b/src/sys/init/init_main.C @@ -25,7 +25,7 @@ void init_main(void* unused) printk("Bringing up VFS..."); task_create(&vfs_main, NULL); task_yield(); // TODO... add a barrier to ensure VFS is fully up. - +/* uint64_t* mmio_addr = (uint64_t*) mmio_map((void*)0x800000000, 1); printk("MMIO Access %llx\n", *mmio_addr); @@ -49,4 +49,8 @@ void init_main(void* unused) for (volatile int i = 0 ; i < 1000000; i++); mutex_unlock(global_mutex); } +*/ + + while(1) + task_yield(); } diff --git a/src/sys/vfs/vfs_main.C b/src/sys/vfs/vfs_main.C index 6ba561eb2..481df1101 100644 --- a/src/sys/vfs/vfs_main.C +++ b/src/sys/vfs/vfs_main.C @@ -10,6 +10,8 @@ const char* VFS_ROOT = "/"; const char* VFS_ROOT_BIN = "/bin/"; const char* VFS_ROOT_DATA = "/data/"; const char* VFS_ROOT_MSG = "/msg/"; +VfsSystemModule VFS_MODULES[VFS_MODULE_MAX]; +uint64_t VFS_LAST_ADDRESS; struct VfsPath { @@ -28,13 +30,34 @@ struct VfsEntry VfsEntry* prev; }; +void vfs_module_init() +{ + printk("Initializing modules.\n"); + + VfsSystemModule* module = &VFS_MODULES[0]; + while ('\0' != module->module[0]) + { + printk("\tIniting module %s...", module->module); + (module->init)(NULL); + printk("done.\n"); + + module++; + } + + printk("Modules initialized."); +} + void vfs_main(void* unused) { + // Create message queue, register with kernel. msg_q_t vfsMsgQ = msg_q_create(); msg_q_register(vfsMsgQ, VFS_ROOT); printk("done.\n"); // TODO... barrier with init. + + // Initalize modules. + vfs_module_init(); Util::Locked::List vfsContents; diff --git a/src/usr/example/example.C b/src/usr/example/example.C new file mode 100644 index 000000000..18095ac5b --- /dev/null +++ b/src/usr/example/example.C @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +static mutex_t value = mutex_create(); + +extern "C" +void _init(void*) +{ + // Call default constructors for any static objects. + extern void (*ctor_start_address)(); + extern void (*ctor_end_address)(); + void(**ctors)() = &ctor_start_address; + while(ctors != &ctor_end_address) + { + (*ctors)(); + ctors++; + } + + printk("Here! %llx, %s\n", (uint64_t) value, VFS_ROOT); +} + +extern "C" +void _start(void*) +{ + task_end(); +} diff --git a/src/usr/example/makefile b/src/usr/example/makefile new file mode 100644 index 000000000..608aacc87 --- /dev/null +++ b/src/usr/example/makefile @@ -0,0 +1,16 @@ +ROOTPATH = ../../.. +OBJDIR = ${ROOTPATH}/obj/modules/example +IMGDIR = ${ROOTPATH}/img +EXTRACOMMONFLAGS = -fPIC + +OBJS = example.o +OBJECTS = $(addprefix ${OBJDIR}/, ${OBJS}) +LIBS = libexample.so +LIBRARIES = $(addprefix ${IMGDIR}/, ${LIBS}) + +all: ${OBJECTS} ${LIBRARIES} + +clean: + (rm -f ${OBJECTS} ${LIBRARIES} ) + +include ${ROOTPATH}/config.mk diff --git a/src/usr/makefile b/src/usr/makefile new file mode 100644 index 000000000..e6907fe8c --- /dev/null +++ b/src/usr/makefile @@ -0,0 +1,9 @@ +ROOTPATH = ../.. + +SUBDIRS = example.d + +all: ${SUBDIRS} + +clean: $(patsubst %.d,%.clean, ${SUBDIRS}) + +include ../../config.mk -- cgit v1.2.1