From 1659920ba06be3fc9dab8bebc165c0fdc65d2a18 Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 10 Oct 2012 13:50:31 +0000 Subject: Add support for the R_ARM_REL32 relocation git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5223 42af7a65-404d-4744-a932-0658087f49c3 --- misc/buildroot/toolchain/nxflat/ldnxflat.c | 235 ++++++++++++++++++----------- 1 file changed, 144 insertions(+), 91 deletions(-) (limited to 'misc/buildroot/toolchain/nxflat/ldnxflat.c') diff --git a/misc/buildroot/toolchain/nxflat/ldnxflat.c b/misc/buildroot/toolchain/nxflat/ldnxflat.c index 69cb19529..5bcdc5da0 100644 --- a/misc/buildroot/toolchain/nxflat/ldnxflat.c +++ b/misc/buildroot/toolchain/nxflat/ldnxflat.c @@ -799,6 +799,134 @@ static void alloc_got_entry(asymbol *sym) } } +/*********************************************************************** + * relocate_arm32 + ***********************************************************************/ + +static void +relocate_arm32(arelent *relp, int32_t *target, symvalue sym_value) +{ + reloc_howto_type *how_to = relp->howto; + asymbol *rel_sym = *relp->sym_ptr_ptr; + asection *rel_section = rel_sym->section; + struct nxflat_reloc_s *relocs; + int32_t temp; + int32_t saved; + int reloc_type; + + /* ABS32 links from .text are easy - since the fetches will + * always be base relative. the ABS32 refs from data will be + * handled the same + */ + + if (verbose > 1) + { + vdbg(" Original location %p is %08lx ", +#ifdef ARCH_BIG_ENDIAN + target, (long)nxflat_swap32(*target)); +#else + target, (long)*target); +#endif + if (verbose > 2) + { + printf("rsh %d ", how_to->rightshift); + printf(" sz %d ", how_to->size); + printf("bit %d ", how_to->bitsize); + printf("rel %d ", how_to->pc_relative); + printf("smask %08lx ", (long)how_to->src_mask); + printf("dmask %08lx ", (long)how_to->dst_mask); + printf("off %d ", how_to->pcrel_offset); + } + + printf("\n"); + } + +#ifdef ARCH_BIG_ENDIAN + saved = temp = (int32_t) nxflat_swap32(*target); +#else + saved = temp = *target; +#endif + /* Mask and sign extend */ + + temp &= how_to->src_mask; + temp <<= (32 - how_to->bitsize); + temp >>= (32 - how_to->bitsize); + + /* Offset */ + + temp += (sym_value + rel_section->vma) >> how_to->rightshift; + + /* Mask upper bits from rollover */ + + temp &= how_to->dst_mask; + + /* Replace data that was masked */ + + temp |= saved & (~how_to->dst_mask); + + vdbg(" Modified location: %08lx\n", (long)temp); +#ifdef ARCH_BIG_ENDIAN + *target = (long)nxflat_swap32(temp); +#else + *target = (long)temp; +#endif + /* Determine where the symbol lies */ + + switch (get_reloc_type(rel_section, NULL)) + { + case NXFLAT_RELOC_TARGET_UNKNOWN: + default: + { + err("Symbol relocation section type is unknown\n"); + nerrors++; + } + /* Fall through and do something wrong */ + + case NXFLAT_RELOC_TARGET_BSS: + case NXFLAT_RELOC_TARGET_DATA: + { + vdbg("Symbol '%s' lies in D-Space\n", rel_sym->name); + reloc_type = NXFLAT_RELOC_TYPE_REL32D; + } + break; + + case NXFLAT_RELOC_TARGET_TEXT: + { + vdbg("Symbol '%s' lies in I-Space\n", rel_sym->name); + reloc_type = NXFLAT_RELOC_TYPE_REL32I; + } + break; + } + + /* Re-allocate memory to include this relocation */ + + relocs = (struct nxflat_reloc_s*) + realloc(nxflat_relocs, sizeof(struct nxflat_reloc_s) * nxflat_nrelocs + 1); + if (!relocs) + { + err("Failed to re-allocate memory ABS32 relocations (%d relocations)\n", + nxflat_nrelocs); + nerrors++; + } + else + { + /* Reallocation was successful. Update globals */ + + nxflat_nrelocs++; + nxflat_relocs = relocs; + + /* Then add the relocation at the end of the table */ + + nxflat_relocs[nxflat_nrelocs-1].r_info = + NXFLAT_RELOC(reloc_type, relp->address + got_size); + + vdbg("relocs[%d]: type: %d offset: %08x\n", + nxflat_nrelocs-1, + NXFLAT_RELOC_TYPE(nxflat_relocs[nxflat_nrelocs-1].r_info), + NXFLAT_RELOC_OFFSET(nxflat_relocs[nxflat_nrelocs-1].r_info)); + } + } + /*********************************************************************** * resolve_segment_relocs ***********************************************************************/ @@ -806,10 +934,8 @@ static void alloc_got_entry(asymbol *sym) static void resolve_segment_relocs(bfd *input_bfd, segment_info *inf, asymbol **syms) { - struct nxflat_reloc_s *relocs; arelent **relpp; int relsize; - int reloc_type; int relcount; int i; int j; @@ -976,68 +1102,22 @@ resolve_segment_relocs(bfd *input_bfd, segment_info *inf, asymbol **syms) case R_ARM_ABS32: { - int32_t temp; - int32_t saved; - dbg("Performing ABS32 link at addr %08lx [%08lx] to sym '%s' [%08lx]\n", (long)relpp[j]->address, (long)*target, rel_sym->name, (long)sym_value); - /* ABS32 links from .text are easy - since the fetches will - * always be base relative. the ABS32 refs from data will be - * handled the same - */ - - if (verbose > 1) - { - vdbg(" Original location %p is %08lx ", -#ifdef ARCH_BIG_ENDIAN - target, (long)nxflat_swap32(*target)); -#else - target, (long)*target); -#endif - if (verbose > 2) - { - printf("rsh %d ", how_to->rightshift); - printf(" sz %d ", how_to->size); - printf("bit %d ", how_to->bitsize); - printf("rel %d ", how_to->pc_relative); - printf("smask %08lx ", (long)how_to->src_mask); - printf("dmask %08lx ", (long)how_to->dst_mask); - printf("off %d ", how_to->pcrel_offset); - } - printf("\n"); - } - -#ifdef ARCH_BIG_ENDIAN - saved = temp = (int32_t) nxflat_swap32(*target); -#else - saved = temp = *target; -#endif - /* Mask and sign extend */ - - temp &= how_to->src_mask; - temp <<= (32 - how_to->bitsize); - temp >>= (32 - how_to->bitsize); - - /* Offset */ - - temp += (sym_value + rel_section->vma) >> how_to->rightshift; - - /* Mask upper bits from rollover */ - - temp &= how_to->dst_mask; - - /* Replace data that was masked */ + relocate_arm32(relpp[j], target, sym_value); + } + break; - temp |= saved & (~how_to->dst_mask); + case R_ARM_REL32: + { + dbg("Performing REL32 link at addr %08lx [%08lx] to sym '%s' [%08lx]\n", + (long)relpp[j]->address, (long)*target, rel_sym->name, (long)sym_value); - vdbg(" Modified location: %08lx\n", (long)temp); -#ifdef ARCH_BIG_ENDIAN - *target = (long)nxflat_swap32(temp); -#else - *target = (long)temp; -#endif - /* Determine where the symbol lies */ + /* The REL32 relocation is just like the ABS32 relocation except that (1) + * the symbol value is relative to the PC, and (2) we cannot permit + * REL32 relocations to data in I-Space. That just would not make sense. + */ switch (get_reloc_type(rel_section, NULL)) { @@ -1047,51 +1127,24 @@ resolve_segment_relocs(bfd *input_bfd, segment_info *inf, asymbol **syms) err("Symbol relocation section type is unknown\n"); nerrors++; } - /* Fall through and do something wrong */ + break; case NXFLAT_RELOC_TARGET_BSS: case NXFLAT_RELOC_TARGET_DATA: { - vdbg("Symbol '%s' lies in D-Space\n", rel_sym->name); - reloc_type = NXFLAT_RELOC_TYPE_REL32D; + err("Cannot perform REL32 relocation: Symbol '%s' lies in D-Space\n", + rel_sym->name); + nerrors++; } break; case NXFLAT_RELOC_TARGET_TEXT: { vdbg("Symbol '%s' lies in I-Space\n", rel_sym->name); - reloc_type = NXFLAT_RELOC_TYPE_REL32I; + relocate_arm32(relpp[j], target, sym_value - relpp[j]->address); } break; } - - /* Re-allocate memory to include this relocation */ - - relocs = (struct nxflat_reloc_s*) - realloc(nxflat_relocs, sizeof(struct nxflat_reloc_s) * nxflat_nrelocs + 1); - if (!relocs) - { - err("Failed to re-allocate memory ABS32 relocations (%d relocations)\n", - nxflat_nrelocs); - nerrors++; - } - else - { - /* Reallocation was successful. Update globlas */ - - nxflat_nrelocs++; - nxflat_relocs = relocs; - - /* Then add the relocation at the end of the table */ - - nxflat_relocs[nxflat_nrelocs-1].r_info = - NXFLAT_RELOC(reloc_type, relpp[j]->address + got_size); - - vdbg("relocs[%d]: type: %d offset: %08x\n", - nxflat_nrelocs-1, - NXFLAT_RELOC_TYPE(nxflat_relocs[nxflat_nrelocs-1].r_info), - NXFLAT_RELOC_OFFSET(nxflat_relocs[nxflat_nrelocs-1].r_info)); - } } break; -- cgit v1.2.3