diff options
author | Patrick Williams <iawillia@us.ibm.com> | 2011-01-11 13:36:10 -0600 |
---|---|---|
committer | Patrick Williams <iawillia@us.ibm.com> | 2011-01-11 13:36:10 -0600 |
commit | 24f8e7b689abcb44ed43666ba4a0ca8fd78ea924 (patch) | |
tree | 2d472f09258893247760dbd2d4000602ac580a24 /src/build/linker | |
parent | 2d712d7c4de500e133e1cb002c9668b721777fd7 (diff) | |
download | blackbird-hostboot-24f8e7b689abcb44ed43666ba4a0ca8fd78ea924.tar.gz blackbird-hostboot-24f8e7b689abcb44ed43666ba4a0ca8fd78ea924.zip |
More updates to build on pool machines.
Diffstat (limited to 'src/build/linker')
-rw-r--r-- | src/build/linker/.gitignore | 1 | ||||
-rw-r--r-- | src/build/linker/linker.C | 495 | ||||
-rw-r--r-- | src/build/linker/makefile | 7 |
3 files changed, 503 insertions, 0 deletions
diff --git a/src/build/linker/.gitignore b/src/build/linker/.gitignore new file mode 100644 index 000000000..6b243f5f3 --- /dev/null +++ b/src/build/linker/.gitignore @@ -0,0 +1 @@ +linker diff --git a/src/build/linker/linker.C b/src/build/linker/linker.C new file mode 100644 index 000000000..fda2059d4 --- /dev/null +++ b/src/build/linker/linker.C @@ -0,0 +1,495 @@ +#include <stdint.h> +#include <bfd.h> +#include <iostream> +#include <string> +#include <vector> +#include <map> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <algorithm> + +#include <vfs.h> + +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<string, Symbol> symbols; + vector<Symbol> 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<Object> objects; +FILE* output; + +int main(int argc, char** argv) +{ + if (argc <= 2) + { + cout << argv[0] << " <output> <kernel> <modules>" << endl; + return -1; + } + + // Open output file. + output = fopen(argv[1], "w+"); + if (NULL == output) + { + int error = errno; + cout << "Error opening " << argv[1] << endl; + cout << strerror(error) << endl; + } + + // Read input objects. + for (int files = 2; files < argc; files++) + { + Object o; + if (o.read_object(argv[files])) + { + o.read_relocation(); + objects.push_back(o); + cout << endl; + } + } + + 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<Object>::iterator i = ++objects.begin(); + i != objects.end(); + ++i) + { + 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; +} + +bool Object::read_object(char* file) +{ + // Open BFD file. + image = bfd_openr(file, NULL); + if (!bfd_check_format(image, bfd_object)) + { + cout << "Unsupported file format: " << file << endl; + return false; + } + + name = file; + cout << "File " << file << endl; + + // Read sections. + bfd_section* image_section = image->sections; + while(image_section != NULL) + { + Section* s = NULL; + if (string(".text") == bfd_get_section_name(image, image_section)) + { + s = &this->text; + } + if (string(".data") == bfd_get_section_name(image, image_section)) + { + s = &this->data; + } + if (NULL != s) + { + s->name = bfd_get_section_name(image, image_section); + s->vma_offset = bfd_get_section_vma(image, image_section); + s->size = bfd_get_section_size(image_section); + + bfd_malloc_and_get_section(image, image_section, &s->data); + + cout << "Section " << s->name << endl; + cout << "\tSize " << std::dec << s->size << endl; + cout << "\tVMA " << std::hex << s->vma_offset << endl; + cout << "\tData " << std::hex << bfd_getb64(s->data) + << "..." << endl; + } + + image_section = image_section->next; + } + + return true; +} + +#define advance_to_page_align(f) \ + { \ + long pos = ftell(f); \ + if (pos % 4096) \ + { \ + fseek((f), 4096 - (pos % 4096), SEEK_CUR); \ + } \ + } + +bool Object::write_object(FILE* file) +{ + // Start outputing object at page boundary. + advance_to_page_align(file); + offset = ftell(file); + + // Output TEXT section. + fseek(file, text.vma_offset, SEEK_CUR); + if (text.size != fwrite(text.data, 1, text.size, file)) + { + int error = errno; + cout << "Error writing to output." << endl; + cout << strerror(error) << endl; + } + + // Output DATA section. + fseek(file, offset + data.vma_offset, SEEK_SET); + if (data.size != fwrite(data.data, 1, data.size, file)) + { + int error = errno; + cout << "Error writing to output." << endl; + 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<Symbol>::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<Symbol>::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<Object>::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/build/linker/makefile b/src/build/linker/makefile new file mode 100644 index 000000000..6df00f183 --- /dev/null +++ b/src/build/linker/makefile @@ -0,0 +1,7 @@ +linker: linker.C + g++ -O3 -g linker.C -o linker -lbfd -I../../include/sys + +all: linker + +clean: + (rm -f linker) |