coff-sh.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,052 行 · 第 1/5 页
C
2,052 行
break; case R_SH_PCRELIMM8BY2: off = insn & 0xff; stop = start + 4 + off * 2; break; case R_SH_PCRELIMM8BY4: off = insn & 0xff; stop = (start &~ (bfd_vma) 3) + 4 + off * 4; break; case R_SH_SWITCH8: case R_SH_SWITCH16: case R_SH_SWITCH32: /* These relocs types represent .word L2-L1 The r_offset field holds the difference between the reloc address and L1. That is the start of the reloc, and adding in the contents gives us the top. We must adjust both the r_offset field and the section contents. */ start = irel->r_vaddr - sec->vma; stop = (bfd_vma) ((bfd_signed_vma) start - (long) irel->r_offset); if (start > addr && start < toaddr && (stop <= addr || stop >= toaddr)) irel->r_offset += count; else if (stop > addr && stop < toaddr && (start <= addr || start >= toaddr)) irel->r_offset -= count; start = stop; if (irel->r_type == R_SH_SWITCH16) voff = bfd_get_signed_16 (abfd, contents + nraddr); else if (irel->r_type == R_SH_SWITCH8) voff = bfd_get_8 (abfd, contents + nraddr); else voff = bfd_get_signed_32 (abfd, contents + nraddr); stop = (bfd_vma) ((bfd_signed_vma) start + voff); break; case R_SH_USES: start = irel->r_vaddr - sec->vma; stop = (bfd_vma) ((bfd_signed_vma) start + (long) irel->r_offset + 4); break; } if (start > addr && start < toaddr && (stop <= addr || stop >= toaddr)) adjust = count; else if (stop > addr && stop < toaddr && (start <= addr || start >= toaddr)) adjust = - count; else adjust = 0; if (adjust != 0) { oinsn = insn; overflow = false; switch (irel->r_type) { default: abort (); break; case R_SH_PCDISP8BY2: case R_SH_PCRELIMM8BY2: insn += adjust / 2; if ((oinsn & 0xff00) != (insn & 0xff00)) overflow = true; bfd_put_16 (abfd, insn, contents + nraddr); break; case R_SH_PCDISP: insn += adjust / 2; if ((oinsn & 0xf000) != (insn & 0xf000)) overflow = true; bfd_put_16 (abfd, insn, contents + nraddr); break; case R_SH_PCRELIMM8BY4: BFD_ASSERT (adjust == count || count >= 4); if (count >= 4) insn += adjust / 4; else { if ((irel->r_vaddr & 3) == 0) ++insn; } if ((oinsn & 0xff00) != (insn & 0xff00)) overflow = true; bfd_put_16 (abfd, insn, contents + nraddr); break; case R_SH_SWITCH8: voff += adjust; if (voff < 0 || voff >= 0xff) overflow = true; bfd_put_8 (abfd, voff, contents + nraddr); break; case R_SH_SWITCH16: voff += adjust; if (voff < - 0x8000 || voff >= 0x8000) overflow = true; bfd_put_signed_16 (abfd, voff, contents + nraddr); break; case R_SH_SWITCH32: voff += adjust; bfd_put_signed_32 (abfd, voff, contents + nraddr); break; case R_SH_USES: irel->r_offset += adjust; break; } if (overflow) { ((*_bfd_error_handler) ("%s: 0x%lx: fatal: reloc overflow while relaxing", bfd_get_filename (abfd), (unsigned long) irel->r_vaddr)); bfd_set_error (bfd_error_bad_value); return false; } } irel->r_vaddr = nraddr + sec->vma; } /* Look through all the other sections. If there contain any IMM32 relocs against internal symbols which we are not going to adjust below, we may need to adjust the addends. */ for (o = abfd->sections; o != NULL; o = o->next) { struct internal_reloc *internal_relocs; struct internal_reloc *irelscan, *irelscanend; bfd_byte *ocontents; if (o == sec || (o->flags & SEC_RELOC) == 0 || o->reloc_count == 0) continue; /* We always cache the relocs. Perhaps, if info->keep_memory is false, we should free them, if we are permitted to, when we leave sh_coff_relax_section. */ internal_relocs = (_bfd_coff_read_internal_relocs (abfd, o, true, (bfd_byte *) NULL, false, (struct internal_reloc *) NULL)); if (internal_relocs == NULL) return false; ocontents = NULL; irelscanend = internal_relocs + o->reloc_count; for (irelscan = internal_relocs; irelscan < irelscanend; irelscan++) { struct internal_syment sym;#ifdef COFF_WITH_PE if (irelscan->r_type != R_SH_IMM32 && irelscan->r_type != R_SH_IMAGEBASE && irelscan->r_type != R_SH_IMM32CE)#else if (irelscan->r_type != R_SH_IMM32)#endif continue; bfd_coff_swap_sym_in (abfd, ((bfd_byte *) obj_coff_external_syms (abfd) + (irelscan->r_symndx * bfd_coff_symesz (abfd))), &sym); if (sym.n_sclass != C_EXT && sym.n_scnum == sec->target_index && ((bfd_vma) sym.n_value <= addr || (bfd_vma) sym.n_value >= toaddr)) { bfd_vma val; if (ocontents == NULL) { if (coff_section_data (abfd, o)->contents != NULL) ocontents = coff_section_data (abfd, o)->contents; else { /* We always cache the section contents. Perhaps, if info->keep_memory is false, we should free them, if we are permitted to, when we leave sh_coff_relax_section. */ ocontents = (bfd_byte *) bfd_malloc (o->_raw_size); if (ocontents == NULL) return false; if (! bfd_get_section_contents (abfd, o, ocontents, (file_ptr) 0, o->_raw_size)) return false; coff_section_data (abfd, o)->contents = ocontents; } } val = bfd_get_32 (abfd, ocontents + irelscan->r_vaddr - o->vma); val += sym.n_value; if (val > addr && val < toaddr) bfd_put_32 (abfd, val - count, ocontents + irelscan->r_vaddr - o->vma); coff_section_data (abfd, o)->keep_contents = true; } } } /* Adjusting the internal symbols will not work if something has already retrieved the generic symbols. It would be possible to make this work by adjusting the generic symbols at the same time. However, this case should not arise in normal usage. */ if (obj_symbols (abfd) != NULL || obj_raw_syments (abfd) != NULL) { ((*_bfd_error_handler) ("%s: fatal: generic symbols retrieved before relaxing", bfd_get_filename (abfd))); bfd_set_error (bfd_error_invalid_operation); return false; } /* Adjust all the symbols. */ sym_hash = obj_coff_sym_hashes (abfd); symesz = bfd_coff_symesz (abfd); esym = (bfd_byte *) obj_coff_external_syms (abfd); esymend = esym + obj_raw_syment_count (abfd) * symesz; while (esym < esymend) { struct internal_syment isym; bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &isym); if (isym.n_scnum == sec->target_index && (bfd_vma) isym.n_value > addr && (bfd_vma) isym.n_value < toaddr) { isym.n_value -= count; bfd_coff_swap_sym_out (abfd, (PTR) &isym, (PTR) esym); if (*sym_hash != NULL) { BFD_ASSERT ((*sym_hash)->root.type == bfd_link_hash_defined || (*sym_hash)->root.type == bfd_link_hash_defweak); BFD_ASSERT ((*sym_hash)->root.u.def.value >= addr && (*sym_hash)->root.u.def.value < toaddr); (*sym_hash)->root.u.def.value -= count; } } esym += (isym.n_numaux + 1) * symesz; sym_hash += isym.n_numaux + 1; } /* See if we can move the ALIGN reloc forward. We have adjusted r_vaddr for it already. */ if (irelalign != NULL) { bfd_vma alignto, alignaddr; alignto = BFD_ALIGN (toaddr, 1 << irelalign->r_offset); alignaddr = BFD_ALIGN (irelalign->r_vaddr - sec->vma, 1 << irelalign->r_offset); if (alignto != alignaddr) { /* Tail recursion. */ return sh_relax_delete_bytes (abfd, sec, alignaddr, alignto - alignaddr); } } return true;}/* This is yet another version of the SH opcode table, used to rapidly get information about a particular instruction. *//* The opcode map is represented by an array of these structures. The array is indexed by the high order four bits in the instruction. */struct sh_major_opcode{ /* A pointer to the instruction list. This is an array which contains all the instructions with this major opcode. */ const struct sh_minor_opcode *minor_opcodes; /* The number of elements in minor_opcodes. */ unsigned short count;};/* This structure holds information for a set of SH opcodes. The instruction code is anded with the mask value, and the resulting value is used to search the order opcode list. */struct sh_minor_opcode{ /* The sorted opcode list. */ const struct sh_opcode *opcodes; /* The number of elements in opcodes. */ unsigned short count; /* The mask value to use when searching the opcode list. */ unsigned short mask;};/* This structure holds information for an SH instruction. An array of these structures is sorted in order by opcode. */struct sh_opcode{ /* The code for this instruction, after it has been anded with the mask value in the sh_major_opcode structure. */ unsigned short opcode; /* Flags for this instruction. */ unsigned long flags;};/* Flag which appear in the sh_opcode structure. *//* This instruction loads a value from memory. */#define LOAD (0x1)/* This instruction stores a value to memory. */#define STORE (0x2)/* This instruction is a branch. */#define BRANCH (0x4)/* This instruction has a delay slot. */#define DELAY (0x8)/* This instruction uses the value in the register in the field at mask 0x0f00 of the instruction. */#define USES1 (0x10)#define USES1_REG(x) ((x & 0x0f00) >> 8)/* This instruction uses the value in the register in the field at mask 0x00f0 of the instruction. */#define USES2 (0x20)#define USES2_REG(x) ((x & 0x00f0) >> 4)/* This instruction uses the value in register 0. */#define USESR0 (0x40)/* This instruction sets the value in the register in the field at mask 0x0f00 of the instruction. */#define SETS1 (0x80)#define SETS1_REG(x) ((x & 0x0f00) >> 8)/* This instruction sets the value in the register in the field at mask 0x00f0 of the instruction. */#define SETS2 (0x100)#define SETS2_REG(x) ((x & 0x00f0) >> 4)/* This instruction sets register 0. */#define SETSR0 (0x200)/* This instruction sets a special register. */#define SETSSP (0x400)/* This instruction uses a special register. */#define USESSP (0x800)/* This instruction uses the floating point register in the field at mask 0x0f00 of the instruction. */#define USESF1 (0x1000)#define USESF1_REG(x) ((x & 0x0f00) >> 8)/* This instruction uses the floating point register in the field at mask 0x00f0 of the instruction. */#define USESF2 (0x2000)#define USESF2_REG(x) ((x & 0x00f0) >> 4)/* This instruction uses floating point register 0. */#define USESF0 (0x4000)/* This instruction sets the floating point register in the field at mask 0x0f00 of the instruction. */#define SETSF1 (0x8000)#define SETSF1_REG(x) ((x & 0x0f00) >> 8)#define USESAS (0x10000)#define USESAS_REG(x) (((((x) >> 8) - 2) & 3) + 2)#define USESR8 (0x20000)#define SETSAS (0x40000)#define SETSAS_REG(x) USESAS_REG (x)#ifndef COFF_IMAGE_WITH_PEstatic boolean sh_insn_uses_reg PARAMS ((unsigned int, const struct sh_opcode *, unsigned int));static boolean sh_insn_sets_reg PARAMS ((unsigned int, const struct sh_opcode *, unsigned int));static boolean sh_insn_uses_or_sets_reg PARAMS ((unsigned int, const struct sh_opcode *, unsigned int));static boolean sh_insn_uses_freg PARAMS ((unsigned int, const struct sh_opcode *, unsigned int));static boolean sh_insn_sets_freg
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?