elf32-v850.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,145 行 · 第 1/5 页
C
2,145 行
0xffff, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* GNU extension to record C++ vtable hierarchy */ HOWTO (R_V850_GNU_VTINHERIT, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ NULL, /* special_function */ "R_V850_GNU_VTINHERIT", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ /* GNU extension to record C++ vtable member usage */ HOWTO (R_V850_GNU_VTENTRY, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ _bfd_elf_rel_vtable_reloc_fn, /* special_function */ "R_V850_GNU_VTENTRY", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */};/* Map BFD reloc types to V850 ELF reloc types. */struct v850_elf_reloc_map{ /* BFD_RELOC_V850_CALLT_16_16_OFFSET is 258, which will not fix in an unsigned char. */ bfd_reloc_code_real_type bfd_reloc_val; unsigned char elf_reloc_val;};static const struct v850_elf_reloc_map v850_elf_reloc_map[] ={ { BFD_RELOC_NONE, R_V850_NONE }, { BFD_RELOC_V850_9_PCREL, R_V850_9_PCREL }, { BFD_RELOC_V850_22_PCREL, R_V850_22_PCREL }, { BFD_RELOC_HI16_S, R_V850_HI16_S }, { BFD_RELOC_HI16, R_V850_HI16 }, { BFD_RELOC_LO16, R_V850_LO16 }, { BFD_RELOC_32, R_V850_32 }, { BFD_RELOC_16, R_V850_16 }, { BFD_RELOC_8, R_V850_8 }, { BFD_RELOC_V850_SDA_16_16_OFFSET, R_V850_SDA_16_16_OFFSET }, { BFD_RELOC_V850_SDA_15_16_OFFSET, R_V850_SDA_15_16_OFFSET }, { BFD_RELOC_V850_ZDA_16_16_OFFSET, R_V850_ZDA_16_16_OFFSET }, { BFD_RELOC_V850_ZDA_15_16_OFFSET, R_V850_ZDA_15_16_OFFSET }, { BFD_RELOC_V850_TDA_6_8_OFFSET, R_V850_TDA_6_8_OFFSET }, { BFD_RELOC_V850_TDA_7_8_OFFSET, R_V850_TDA_7_8_OFFSET }, { BFD_RELOC_V850_TDA_7_7_OFFSET, R_V850_TDA_7_7_OFFSET }, { BFD_RELOC_V850_TDA_16_16_OFFSET, R_V850_TDA_16_16_OFFSET }, { BFD_RELOC_V850_TDA_4_5_OFFSET, R_V850_TDA_4_5_OFFSET }, { BFD_RELOC_V850_TDA_4_4_OFFSET, R_V850_TDA_4_4_OFFSET }, { BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, R_V850_SDA_16_16_SPLIT_OFFSET }, { BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, R_V850_ZDA_16_16_SPLIT_OFFSET }, { BFD_RELOC_V850_CALLT_6_7_OFFSET, R_V850_CALLT_6_7_OFFSET }, { BFD_RELOC_V850_CALLT_16_16_OFFSET, R_V850_CALLT_16_16_OFFSET }, { BFD_RELOC_VTABLE_INHERIT, R_V850_GNU_VTINHERIT }, { BFD_RELOC_VTABLE_ENTRY, R_V850_GNU_VTENTRY },};/* Map a bfd relocation into the appropriate howto structure */static reloc_howto_type *v850_elf_reloc_type_lookup (abfd, code) bfd * abfd ATTRIBUTE_UNUSED; bfd_reloc_code_real_type code;{ unsigned int i; for (i = 0; i < sizeof (v850_elf_reloc_map) / sizeof (struct v850_elf_reloc_map); i++) { if (v850_elf_reloc_map[i].bfd_reloc_val == code) { BFD_ASSERT (v850_elf_howto_table[v850_elf_reloc_map[i].elf_reloc_val].type == v850_elf_reloc_map[i].elf_reloc_val); return & v850_elf_howto_table[v850_elf_reloc_map[i].elf_reloc_val]; } } return NULL;}/* Set the howto pointer for an V850 ELF reloc. */static voidv850_elf_info_to_howto_rel (abfd, cache_ptr, dst) bfd * abfd ATTRIBUTE_UNUSED; arelent * cache_ptr; Elf32_Internal_Rel * dst;{ unsigned int r_type; r_type = ELF32_R_TYPE (dst->r_info); BFD_ASSERT (r_type < (unsigned int) R_V850_max); cache_ptr->howto = &v850_elf_howto_table[r_type];}/* Set the howto pointer for a V850 ELF reloc (type RELA). */static voidv850_elf_info_to_howto_rela (abfd, cache_ptr, dst) bfd * abfd ATTRIBUTE_UNUSED; arelent * cache_ptr; Elf32_Internal_Rela *dst;{ unsigned int r_type; r_type = ELF32_R_TYPE (dst->r_info); BFD_ASSERT (r_type < (unsigned int) R_V850_max); cache_ptr->howto = &v850_elf_howto_table[r_type];}/* Look through the relocs for a section during the first phase, and allocate space in the global offset table or procedure linkage table. */static booleanv850_elf_check_relocs (abfd, info, sec, relocs) bfd * abfd; struct bfd_link_info * info; asection * sec; const Elf_Internal_Rela * relocs;{ boolean ret = true; bfd *dynobj; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; asection *sreloc; enum v850_reloc_type r_type; int other = 0; const char *common = (const char *)0; if (info->relocateable) return true;#ifdef DEBUG fprintf (stderr, "v850_elf_check_relocs called for section %s in %s\n", bfd_get_section_name (abfd, sec), bfd_get_filename (abfd));#endif dynobj = elf_hash_table (info)->dynobj; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); sreloc = NULL; rel_end = relocs + sec->reloc_count; for (rel = relocs; rel < rel_end; rel++) { unsigned long r_symndx; struct elf_link_hash_entry *h; r_symndx = ELF32_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) h = NULL; else h = sym_hashes[r_symndx - symtab_hdr->sh_info]; r_type = (enum v850_reloc_type) ELF32_R_TYPE (rel->r_info); switch (r_type) { default: case R_V850_NONE: case R_V850_9_PCREL: case R_V850_22_PCREL: case R_V850_HI16_S: case R_V850_HI16: case R_V850_LO16: case R_V850_32: case R_V850_16: case R_V850_8: case R_V850_CALLT_6_7_OFFSET: case R_V850_CALLT_16_16_OFFSET: break; /* This relocation describes the C++ object vtable hierarchy. Reconstruct it for later use during GC. */ case R_V850_GNU_VTINHERIT: if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) return false; break; /* This relocation describes which C++ vtable entries are actually used. Record for later use during GC. */ case R_V850_GNU_VTENTRY: if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend)) return false; break; case R_V850_SDA_16_16_SPLIT_OFFSET: case R_V850_SDA_16_16_OFFSET: case R_V850_SDA_15_16_OFFSET: other = V850_OTHER_SDA; common = ".scommon"; goto small_data_common; case R_V850_ZDA_16_16_SPLIT_OFFSET: case R_V850_ZDA_16_16_OFFSET: case R_V850_ZDA_15_16_OFFSET: other = V850_OTHER_ZDA; common = ".zcommon"; goto small_data_common; case R_V850_TDA_4_5_OFFSET: case R_V850_TDA_4_4_OFFSET: case R_V850_TDA_6_8_OFFSET: case R_V850_TDA_7_8_OFFSET: case R_V850_TDA_7_7_OFFSET: case R_V850_TDA_16_16_OFFSET: other = V850_OTHER_TDA; common = ".tcommon"; /* fall through */#define V850_OTHER_MASK (V850_OTHER_TDA | V850_OTHER_SDA | V850_OTHER_ZDA) small_data_common: if (h) { h->other |= other; /* flag which type of relocation was used */ if ((h->other & V850_OTHER_MASK) != (other & V850_OTHER_MASK) && (h->other & V850_OTHER_ERROR) == 0) { const char * msg; static char buff[200]; /* XXX */ switch (h->other & V850_OTHER_MASK) { default: msg = _("Variable `%s' cannot occupy in multiple small data regions"); break; case V850_OTHER_SDA | V850_OTHER_ZDA | V850_OTHER_TDA: msg = _("Variable `%s' can only be in one of the small, zero, and tiny data regions"); break; case V850_OTHER_SDA | V850_OTHER_ZDA: msg = _("Variable `%s' cannot be in both small and zero data regions simultaneously"); break; case V850_OTHER_SDA | V850_OTHER_TDA: msg = _("Variable `%s' cannot be in both small and tiny data regions simultaneously"); break; case V850_OTHER_ZDA | V850_OTHER_TDA: msg = _("Variable `%s' cannot be in both zero and tiny data regions simultaneously"); break; } sprintf (buff, msg, h->root.root.string); info->callbacks->warning (info, buff, h->root.root.string, abfd, h->root.u.def.section, 0); bfd_set_error (bfd_error_bad_value); h->other |= V850_OTHER_ERROR; ret = false; } } if (h && h->root.type == bfd_link_hash_common && h->root.u.c.p && !strcmp (bfd_get_section_name (abfd, h->root.u.c.p->section), "COMMON")) { asection *section = h->root.u.c.p->section = bfd_make_section_old_way (abfd, common); section->flags |= SEC_IS_COMMON; }#ifdef DEBUG fprintf (stderr, "v850_elf_check_relocs, found %s relocation for %s%s\n", v850_elf_howto_table[ (int)r_type ].name, (h && h->root.root.string) ? h->root.root.string : "<unknown>", (h->root.type == bfd_link_hash_common) ? ", symbol is common" : "");#endif break; } } return ret;}/* * In the old version, when an entry was checked out from the table, * it was deleted. This produced an error if the entry was needed * more than once, as the second attempted retry failed. * * In the current version, the entry is not deleted, instead we set * the field 'found' to true. If a second lookup matches the same * entry, then we know that the hi16s reloc has already been updated * and does not need to be updated a second time. * * TODO - TOFIX: If it is possible that we need to restore 2 different * addresses from the same table entry, where the first generates an * overflow, whilst the second do not, then this code will fail. */typedef struct hi16s_location{ bfd_vma addend; bfd_byte * address; unsigned long counter; boolean found; struct hi16s_location * next;}hi16s_location;static hi16s_location * previous_hi16s;static hi16s_location * free_hi16s;static unsigned long hi16s_counter;static voidremember_hi16s_reloc (abfd, addend, address) bfd * abfd; bfd_vma addend; bfd_byte * address;{ hi16s_location * entry = NULL; /* Find a free structure. */ if (free_hi16s == NULL) free_hi16s = (hi16s_location *) bfd_zalloc (abfd, sizeof (* free_hi16s)); entry = free_hi16s; free_hi16s = free_hi16s->next; entry->addend = addend; entry->address = address; entry->counter = hi16s_counter ++; entry->found = false; entry->next = previous_hi16s; previous_hi16s = entry; /* Cope with wrap around of our counter. */ if (hi16s_counter == 0) { /* XXX - Assume that all counter entries differ only in their low 16 bits. */ for (entry = previous_hi16s; entry != NULL; entry = entry->next) entry->counter &= 0xffff; hi16s_counter = 0x10000; } return;}static bfd_byte *find_remembered_hi16s_reloc (addend, already_found) bfd_vma addend; boolean * already_found;{ hi16s_location * match = NULL; hi16s_location * entry; hi16s_location * previous = NULL; hi16s_location * prev; bfd_byte * addr; /* Search the table. Record the most recent entry that matches. */ for (entry = previous_hi16s; entry; entry = entry->next) { if (entry->addend == addend && (match == NULL || match->counter < entry->counter)) { previous = prev; match = entry; } prev = entry; } if (match == NULL) return NULL; /* Extract the address. */ addr = match->address; /* Remeber if this entry has already been used before. */ if (already_found) * already_found = match->found; /* Note that this entry has now been used. */ match->found = true; return addr;}/* FIXME: The code here probably ought to be removed and the code in reloc.c allowed to do its stuff instead. At least for most of the relocs, anwyay. */static bfd_reloc_status_typev850_elf_perform_relocation (abfd, r_type, addend, address) bfd * abfd; int r_type; bfd_vma addend; bfd_byte * address;{ unsigned long insn; bfd_signed_vma saddend = (bfd_signed_vma) addend; switch (r_type) { default: /* fprintf (stderr, "reloc type %d not SUPPORTED\n", r_type ); */ return bfd_reloc_notsupported; case R_V850_32: bfd_put_32 (abfd, addend, address); return bfd_reloc_ok; case R_V850_22_PCREL: if (saddend > 0x1fffff || saddend < -0x200000) return bfd_reloc_overflow; if ((addend % 2) != 0) return bfd_reloc_dangerous; insn = bfd_get_32 (abfd, address); insn &= ~0xfffe003f; insn |= (((addend & 0xfffe) << 16) | ((addend & 0x3f0000) >> 16)); bfd_put_32 (abfd, insn, address);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?