From a408634ee13315868a80484bd53c579096bec54e Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 12 Dec 2012 21:54:24 +1100 Subject: Relocation is almost working for RAP files. --- rtl-elf.c | 14 ++-- rtl-rap.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 225 insertions(+), 33 deletions(-) diff --git a/rtl-elf.c b/rtl-elf.c index 76bdf1b..d1d97dc 100644 --- a/rtl-elf.c +++ b/rtl-elf.c @@ -148,7 +148,7 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj, const char* symname = NULL; off_t off; Elf_Word type; - Elf_Word symvalue; + Elf_Word symvalue = 0; bool relocate; off = obj->ooffset + sect->offset + (reloc * reloc_size); @@ -234,9 +234,9 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj, if (is_rela) { if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf ("rtl: rela: sym:%s(%-2d) type:%-2d off:%08lx addend:%d\n", - symname, (int) ELF_R_SYM (rela->r_info), (int) ELF_R_TYPE (rela->r_info), - rela->r_offset, (int) rela->r_addend); + printf ("rtl: rela: sym:%s(%-2d)=%08lx type:%-2d off:%08lx addend:%d\n", + symname, (int) ELF_R_SYM (rela->r_info), symvalue, + (int) ELF_R_TYPE (rela->r_info), rela->r_offset, (int) rela->r_addend); if (!rtems_rtl_elf_relocate_rela (obj, rela, targetsect, symname, sym.st_info, symvalue)) return false; @@ -244,9 +244,9 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj, else { if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf ("rtl: rel: sym:%s(%-2d) type:%-2d off:%08lx\n", - symname, (int) ELF_R_SYM (rel->r_info), (int) ELF_R_TYPE (rel->r_info), - rel->r_offset); + printf ("rtl: rel: sym:%s(%-2d)=%08lx type:%-2d off:%08lx\n", + symname, (int) ELF_R_SYM (rel->r_info), symvalue, + (int) ELF_R_TYPE (rel->r_info), rel->r_offset); if (!rtems_rtl_elf_relocate_rel (obj, rel, targetsect, symname, sym.st_info, symvalue)) return false; diff --git a/rtl-rap.c b/rtl-rap.c index d8efcf8..bfedbb0 100644 --- a/rtl-rap.c +++ b/rtl-rap.c @@ -81,7 +81,6 @@ typedef struct rtems_rtl_rap_section_s { uint32_t size; /**< The size of the section. */ uint32_t alignment; /**< The alignment of the section. */ - uint32_t offset; /**< The offset of the section. */ } rtems_rtl_rap_section_t; /** @@ -102,6 +101,7 @@ typedef struct rtems_rtl_rap_s uint32_t fini; /**< The finish strtab offset. */ rtems_rtl_rap_section_t secs[RTEMS_RTL_RAP_SECS]; /**< The sections. */ uint32_t symtab_size; /**< The symbol table size. */ + char* strtab; /**< The string table. */ uint32_t strtab_size; /**< The string table size. */ uint32_t relocs_size; /**< The relocation table size. */ uint32_t symbols; /**< The number of symbols. */ @@ -167,7 +167,14 @@ rtems_rtl_rap_class_check (uint32_t class) static uint32_t rtems_rtl_rap_get_uint32 (const uint8_t* buffer) { - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; + uint32_t value = 0; + int b; + for (b = 0; b < sizeof (uint32_t); ++b) + { + value <<= 8; + value |= buffer[b]; + } + return value; } static bool @@ -194,20 +201,208 @@ rtems_rtl_rap_loader (rtems_rtl_obj_t* obj, } static bool -rtems_rtl_rap_symbols (rtems_rtl_obj_t* obj, - int fd, - rtems_rtl_obj_sect_t* sect, - void* data) +rtems_rtl_rap_relocate (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj) { - return true; -} + #define SYMNAME_BUFFER_SIZE (1024) + char* symname_buffer = NULL; + int section; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: relocation\n"); + + symname_buffer = malloc (SYMNAME_BUFFER_SIZE); + if (!symname_buffer) + { + rtems_rtl_set_error (ENOMEM, "no memory for local symbol name buffer"); + return false; + } + + for (section = 0; section < RTEMS_RTL_RAP_SECS; ++section) + { + rtems_rtl_obj_sect_t* targetsect; + uint32_t header = 0; + int relocs; + bool is_rela; + int r; + + targetsect = rtems_rtl_obj_find_section (obj, rap_sections[section].name); + + if (!targetsect) + { + rtems_rtl_set_error (EINVAL, "no target section found"); + free (symname_buffer); + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &header)) + { + free (symname_buffer); + return false; + } + + /* + * Bit 31 of the header indicates if the relocations for this section + * have a valid addend field. + */ + + is_rela = (header & (1 << 31)) != 0 ? true : false; + relocs = header & ~(1 << 31); + + if (relocs && rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: relocation: %s: header: %08lx relocs: %d %s\n", + rap_sections[section].name, + header, relocs, is_rela ? "rela" : "rel"); + + for (r = 0; r < relocs; ++r) + { + uint32_t info = 0; + uint32_t offset = 0; + uint32_t addend = 0; + Elf_Word type; + const char* symname = NULL; + uint32_t symname_size; + Elf_Word symtype = 0; + Elf_Word symvalue = 0; + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &info)) + { + free (symname_buffer); + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &offset)) + { + free (symname_buffer); + return false; + } + + /* + * The types are: + * + * 0 Section symbol offset in addend. + * 1 Symbol appended to the relocation record. + * 2 Symbol is in the strtabl. + * + * If type 2 bits 30:8 is the offset in the strtab. If type 1 the bits + * are the size of the string. The lower 8 bits of the info field if the + * ELF relocation type field. + */ + + if (((info & (1 << 31)) == 0) || is_rela) + { + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &addend)) + { + free (symname_buffer); + return false; + } + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf (" %2d: info=%08lx offset=%lu addend=%lu\n", + r, info, offset, addend); + + type = info & 0xff; + + if ((info & (1 << 31)) == 0) + { + rtems_rtl_obj_sect_t* symsect; + + symsect = rtems_rtl_obj_find_section_by_index (obj, info >> 8); + if (!symsect) + { + free (symname_buffer); + return false; + } + + symvalue = (Elf_Word) symsect->base; + } + else if (rtems_rtl_elf_rel_resolve_sym (type)) + { + rtems_rtl_obj_sym_t* symbol; + + symname_size = (info & ~(3 << 30)) >> 8; + + if ((info & (1 << 30)) != 0) + { + symname = rap->strtab + symname_size; + } + else + { + if (symname_size > (SYMNAME_BUFFER_SIZE - 1)) + { + free (symname_buffer); + rtems_rtl_set_error (EINVAL, "reloc symbol too big"); + return false; + } + + if (!rtems_rtl_obj_comp_read (rap->decomp, symname_buffer, symname_size)) + { + free (symname_buffer); + return false; + } + + symname_buffer[symname_size] = '\0'; + symname = symname_buffer; + } + + symbol = rtems_rtl_symbol_obj_find (obj, symname); + + if (!symbol) + { + free (symname_buffer); + rtems_rtl_set_error (EINVAL, "global symbol not found: %s", symname); + return false; + } + + symvalue = (Elf_Word) symbol->value; + } + + if (is_rela) + { + Elf_Rela rela; + + rela.r_offset = offset; + rela.r_info = type; + rela.r_addend = addend; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf (" %2d: rela: type:%-2d off:%lu addend:%d" \ + " symname=%s symtype=%lu symvalue=0x%08lx\n", + r, (int) type, offset, (int) addend, + symname, symtype, symvalue); + + if (!rtems_rtl_elf_relocate_rela (obj, &rela, targetsect, + symname, symtype, symvalue)) + { + free (symname_buffer); + return false; + } + } + else + { + Elf_Rel rel; + + rel.r_offset = offset; + rel.r_info = type; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf (" %2d: rel: type:%-2d off:%lu" \ + " symname=%s symtype=%lu symvalue=0x%08lx\n", + r, (int) type, offset, + symname, symtype, symvalue); + + if (!rtems_rtl_elf_relocate_rel (obj, &rel, targetsect, + symname, symtype, symvalue)) + { + free (symname_buffer); + return false; + } + } + } + } + + free (symname_buffer); -static bool -rtems_rtl_rap_relocator (rtems_rtl_obj_t* obj, - int fd, - rtems_rtl_obj_sect_t* sect, - void* data) -{ return true; } @@ -232,8 +427,8 @@ rtems_rtl_rap_load_symbols (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj) obj->global_syms = rap->symbols; - string = (((char*) obj->global_table) + - (rap->symbols * sizeof (rtems_rtl_obj_sym_t))); + rap->strtab = string = (((char*) obj->global_table) + + (rap->symbols * sizeof (rtems_rtl_obj_sym_t))); if (!rtems_rtl_obj_comp_read (rap->decomp, string, rap->strtab_size)) return false; @@ -270,7 +465,7 @@ rtems_rtl_rap_load_symbols (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj) obj->global_table = NULL; obj->global_syms = 0; obj->global_size = 0; - rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", string); + rtems_rtl_set_error (EINVAL, "duplicate global symbol: %s", string); return false; } @@ -281,6 +476,7 @@ rtems_rtl_rap_load_symbols (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj) obj->global_table = NULL; obj->global_syms = 0; obj->global_size = 0; + rtems_rtl_set_error (EINVAL, "section index not found: %lu", data >> 16); return false; } @@ -494,7 +690,7 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd) /* * uint32_t: init * uint32_t: fini - * uint32_t: symtabl_size + * uint32_t: symtab_size * uint32_t: strtab_size * uint32_t: relocs_size */ @@ -545,21 +741,17 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd) if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.secs[section].alignment)) return false; - if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.secs[section].offset)) - return false; - if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT)) - printf ("rtl: rap: %s: size=%lu align=%lu off=%lu\n", + printf ("rtl: rap: %s: size=%lu align=%lu\n", rap_sections[section].name, rap.secs[section].size, - rap.secs[section].alignment, - rap.secs[section].offset); + rap.secs[section].alignment); if (!rtems_rtl_obj_add_section (obj, section, rap_sections[section].name, rap.secs[section].size, - rap.secs[section].offset, + 0, rap.secs[section].alignment, 0, 0, rap_sections[section].flags)) @@ -574,7 +766,7 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd) if (!rtems_rtl_rap_load_symbols (&rap, obj)) return false; - if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_rap_relocator, &rap)) + if (!rtems_rtl_rap_relocate (&rap, obj)) return false; return true; -- cgit v1.2.3