elf32-sh.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,188 行 · 第 1/5 页
C
2,188 行
} /* Look for load and store instructions that we can align on four byte boundaries. */ if (have_code) { boolean swapped; /* Get the section contents. */ if (contents == NULL) { if (elf_section_data (sec)->this_hdr.contents != NULL) contents = elf_section_data (sec)->this_hdr.contents; else { contents = (bfd_byte *) bfd_malloc (sec->_raw_size); if (contents == NULL) goto error_return; free_contents = contents; if (! bfd_get_section_contents (abfd, sec, contents, (file_ptr) 0, sec->_raw_size)) goto error_return; } } if (! sh_elf_align_loads (abfd, sec, internal_relocs, contents, &swapped)) goto error_return; if (swapped) { elf_section_data (sec)->relocs = internal_relocs; free_relocs = NULL; elf_section_data (sec)->this_hdr.contents = contents; free_contents = NULL; symtab_hdr->contents = (bfd_byte *) extsyms; free_extsyms = NULL; } } if (free_relocs != NULL) { free (free_relocs); free_relocs = NULL; } if (free_contents != NULL) { if (! link_info->keep_memory) free (free_contents); else { /* Cache the section contents for elf_link_input_bfd. */ elf_section_data (sec)->this_hdr.contents = contents; } free_contents = NULL; } if (free_extsyms != NULL) { if (! link_info->keep_memory) free (free_extsyms); else { /* Cache the symbols for elf_link_input_bfd. */ symtab_hdr->contents = extsyms; } free_extsyms = NULL; } return true; error_return: if (free_relocs != NULL) free (free_relocs); if (free_contents != NULL) free (free_contents); if (free_extsyms != NULL) free (free_extsyms); return false;}/* Delete some bytes from a section while relaxing. FIXME: There is a lot of duplication between this function and sh_relax_delete_bytes in coff-sh.c. */static booleansh_elf_relax_delete_bytes (abfd, sec, addr, count) bfd *abfd; asection *sec; bfd_vma addr; int count;{ Elf_Internal_Shdr *symtab_hdr; Elf32_External_Sym *extsyms; int shndx, index; bfd_byte *contents; Elf_Internal_Rela *irel, *irelend; Elf_Internal_Rela *irelalign; bfd_vma toaddr; Elf32_External_Sym *esym, *esymend; struct elf_link_hash_entry *sym_hash; asection *o; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; extsyms = (Elf32_External_Sym *) symtab_hdr->contents; shndx = _bfd_elf_section_from_bfd_section (abfd, sec); contents = elf_section_data (sec)->this_hdr.contents; /* The deletion must stop at the next ALIGN reloc for an aligment power larger than the number of bytes we are deleting. */ irelalign = NULL; toaddr = sec->_cooked_size; irel = elf_section_data (sec)->relocs; irelend = irel + sec->reloc_count; for (; irel < irelend; irel++) { if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_ALIGN && irel->r_offset > addr && count < (1 << irel->r_addend)) { irelalign = irel; toaddr = irel->r_offset; break; } } /* Actually delete the bytes. */ memmove (contents + addr, contents + addr + count, toaddr - addr - count); if (irelalign == NULL) sec->_cooked_size -= count; else { int i;#define NOP_OPCODE (0x0009) BFD_ASSERT ((count & 1) == 0); for (i = 0; i < count; i += 2) bfd_put_16 (abfd, NOP_OPCODE, contents + toaddr - count + i); } /* Adjust all the relocs. */ for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) { bfd_vma nraddr, stop; bfd_vma start = 0; int insn = 0; Elf_Internal_Sym sym; int off, adjust, oinsn; bfd_signed_vma voff = 0; boolean overflow; /* Get the new reloc address. */ nraddr = irel->r_offset; if ((irel->r_offset > addr && irel->r_offset < toaddr) || (ELF32_R_TYPE (irel->r_info) == (int) R_SH_ALIGN && irel->r_offset == toaddr)) nraddr -= count; /* See if this reloc was for the bytes we have deleted, in which case we no longer care about it. Don't delete relocs which represent addresses, though. */ if (irel->r_offset >= addr && irel->r_offset < addr + count && ELF32_R_TYPE (irel->r_info) != (int) R_SH_ALIGN && ELF32_R_TYPE (irel->r_info) != (int) R_SH_CODE && ELF32_R_TYPE (irel->r_info) != (int) R_SH_DATA && ELF32_R_TYPE (irel->r_info) != (int) R_SH_LABEL) irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), (int) R_SH_NONE); /* If this is a PC relative reloc, see if the range it covers includes the bytes we have deleted. */ switch ((enum elf_sh_reloc_type) ELF32_R_TYPE (irel->r_info)) { default: break; case R_SH_DIR8WPN: case R_SH_IND12W: case R_SH_DIR8WPZ: case R_SH_DIR8WPL: start = irel->r_offset; insn = bfd_get_16 (abfd, contents + nraddr); break; } switch ((enum elf_sh_reloc_type) ELF32_R_TYPE (irel->r_info)) { default: start = stop = addr; break; case R_SH_DIR32: /* If this reloc is against a symbol defined in this section, and the symbol will not be adjusted below, we must check the addend to see it will put the value in range to be adjusted, and hence must be changed. */ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) { bfd_elf32_swap_symbol_in (abfd, extsyms + ELF32_R_SYM (irel->r_info), &sym); if (sym.st_shndx == shndx && (sym.st_value <= addr || sym.st_value >= toaddr)) { bfd_vma val; val = bfd_get_32 (abfd, contents + nraddr); val += sym.st_value; if (val > addr && val < toaddr) bfd_put_32 (abfd, val - count, contents + nraddr); } } start = stop = addr; break; case R_SH_DIR8WPN: off = insn & 0xff; if (off & 0x80) off -= 0x100; stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); break; case R_SH_IND12W: if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info) start = stop = addr; else { off = insn & 0xfff; if (off & 0x800) off -= 0x1000; stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); } break; case R_SH_DIR8WPZ: off = insn & 0xff; stop = start + 4 + off * 2; break; case R_SH_DIR8WPL: 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_addend 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. N.B. in gas / coff bfd, the elf bfd r_addend is called r_offset, and the elf bfd r_offset is called r_vaddr. */ stop = irel->r_offset; start = (bfd_vma) ((bfd_signed_vma) stop - (long) irel->r_addend); if (start > addr && start < toaddr && (stop <= addr || stop >= toaddr)) irel->r_addend += count; else if (stop > addr && stop < toaddr && (start <= addr || start >= toaddr)) irel->r_addend -= count; if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_SWITCH16) voff = bfd_get_signed_16 (abfd, contents + nraddr); else if (ELF32_R_TYPE (irel->r_info) == (int) 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_offset; stop = (bfd_vma) ((bfd_signed_vma) start + (long) irel->r_addend + 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 ((enum elf_sh_reloc_type) ELF32_R_TYPE (irel->r_info)) { default: abort (); break; case R_SH_DIR8WPN: case R_SH_DIR8WPZ: insn += adjust / 2; if ((oinsn & 0xff00) != (insn & 0xff00)) overflow = true; bfd_put_16 (abfd, insn, contents + nraddr); break; case R_SH_IND12W: insn += adjust / 2; if ((oinsn & 0xf000) != (insn & 0xf000)) overflow = true; bfd_put_16 (abfd, insn, contents + nraddr); break; case R_SH_DIR8WPL: BFD_ASSERT (adjust == count || count >= 4); if (count >= 4) insn += adjust / 4; else { if ((irel->r_offset & 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_addend += adjust; break; } if (overflow) { ((*_bfd_error_handler) (_("%s: 0x%lx: fatal: reloc overflow while relaxing"), bfd_get_filename (abfd), (unsigned long) irel->r_offset)); bfd_set_error (bfd_error_bad_value); return false; } } irel->r_offset = nraddr; } /* 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) { Elf_Internal_Rela *internal_relocs; Elf_Internal_Rela *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_elf32_link_read_relocs (abfd, o, (PTR) NULL, (Elf_Internal_Rela *) NULL, true)); if (internal_relocs == NULL) return false; ocontents = NULL; irelscanend = internal_relocs + o->reloc_count; for (irelscan = internal_relocs; irelscan < irelscanend; irelscan++) { Elf_Internal_Sym sym; /* Dwarf line numbers use R_SH_SWITCH32 relocs. */ if (ELF32_R_TYPE (irelscan->r_info) == (int) R_SH_SWITCH32) { bfd_vma start, stop; bfd_signed_vma voff; if (ocontents == NULL) { if (elf_section_data (o)->this_hdr.contents != NULL) ocontents = elf_section_data (o)->this_hdr.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; elf_section_data (o)->this_hdr.contents = ocontents;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?