coff-sh.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,052 行 · 第 1/5 页
C
2,052 行
&sym); if (sym.n_scnum != 0 && sym.n_scnum != sec->target_index) { ((*_bfd_error_handler) ("%s: 0x%lx: warning: symbol in unexpected section", bfd_get_filename (abfd), (unsigned long) paddr)); continue; } if (sym.n_sclass != C_EXT) { symval = (sym.n_value - sec->vma + sec->output_section->vma + sec->output_offset); } else { struct coff_link_hash_entry *h; h = obj_coff_sym_hashes (abfd)[irelfn->r_symndx]; BFD_ASSERT (h != NULL); if (h->root.type != bfd_link_hash_defined && h->root.type != bfd_link_hash_defweak) { /* This appears to be a reference to an undefined symbol. Just ignore it--it will be caught by the regular reloc processing. */ continue; } symval = (h->root.u.def.value + h->root.u.def.section->output_section->vma + h->root.u.def.section->output_offset); } symval += bfd_get_32 (abfd, contents + paddr - sec->vma); /* See if this function call can be shortened. */ foff = (symval - (irel->r_vaddr - sec->vma + sec->output_section->vma + sec->output_offset + 4)); if (foff < -0x1000 || foff >= 0x1000) { /* After all that work, we can't shorten this function call. */ continue; } /* Shorten the function call. */ /* For simplicity of coding, we are going to modify the section contents, the section relocs, and the BFD symbol table. We must tell the rest of the code not to free up this information. It would be possible to instead create a table of changes which have to be made, as is done in coff-mips.c; that would be more work, but would require less memory when the linker is run. */ if (coff_section_data (abfd, sec) == NULL) { sec->used_by_bfd = ((PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata))); if (sec->used_by_bfd == NULL) goto error_return; } coff_section_data (abfd, sec)->relocs = internal_relocs; coff_section_data (abfd, sec)->keep_relocs = true; free_relocs = NULL; coff_section_data (abfd, sec)->contents = contents; coff_section_data (abfd, sec)->keep_contents = true; free_contents = NULL; obj_coff_keep_syms (abfd) = true; /* Replace the jsr with a bsr. */ /* Change the R_SH_USES reloc into an R_SH_PCDISP reloc, and replace the jsr with a bsr. */ irel->r_type = R_SH_PCDISP; irel->r_symndx = irelfn->r_symndx; if (sym.n_sclass != C_EXT) { /* If this needs to be changed because of future relaxing, it will be handled here like other internal PCDISP relocs. */ bfd_put_16 (abfd, 0xb000 | ((foff >> 1) & 0xfff), contents + irel->r_vaddr - sec->vma); } else { /* We can't fully resolve this yet, because the external symbol value may be changed by future relaxing. We let the final link phase handle it. */ bfd_put_16 (abfd, 0xb000, contents + irel->r_vaddr - sec->vma); } /* See if there is another R_SH_USES reloc referring to the same register load. */ for (irelscan = internal_relocs; irelscan < irelend; irelscan++) if (irelscan->r_type == R_SH_USES && laddr == irelscan->r_vaddr - sec->vma + 4 + irelscan->r_offset) break; if (irelscan < irelend) { /* Some other function call depends upon this register load, and we have not yet converted that function call. Indeed, we may never be able to convert it. There is nothing else we can do at this point. */ continue; } /* Look for a R_SH_COUNT reloc on the location where the function address is stored. Do this before deleting any bytes, to avoid confusion about the address. */ for (irelcount = internal_relocs; irelcount < irelend; irelcount++) if (irelcount->r_vaddr == paddr && irelcount->r_type == R_SH_COUNT) break; /* Delete the register load. */ if (! sh_relax_delete_bytes (abfd, sec, laddr, 2)) goto error_return; /* That will change things, so, just in case it permits some other function call to come within range, we should relax again. Note that this is not required, and it may be slow. */ *again = true; /* Now check whether we got a COUNT reloc. */ if (irelcount >= irelend) { ((*_bfd_error_handler) ("%s: 0x%lx: warning: could not find expected COUNT reloc", bfd_get_filename (abfd), (unsigned long) paddr)); continue; } /* The number of uses is stored in the r_offset field. We've just deleted one. */ if (irelcount->r_offset == 0) { ((*_bfd_error_handler) ("%s: 0x%lx: warning: bad count", bfd_get_filename (abfd), (unsigned long) paddr)); continue; } --irelcount->r_offset; /* If there are no more uses, we can delete the address. Reload the address from irelfn, in case it was changed by the previous call to sh_relax_delete_bytes. */ if (irelcount->r_offset == 0) { if (! sh_relax_delete_bytes (abfd, sec, irelfn->r_vaddr - sec->vma, 4)) goto error_return; } /* We've done all we can with that function call. */ } /* 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 (coff_section_data (abfd, sec) != NULL && coff_section_data (abfd, sec)->contents != NULL) contents = coff_section_data (abfd, sec)->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_align_loads (abfd, sec, internal_relocs, contents, &swapped)) goto error_return; if (swapped) { if (coff_section_data (abfd, sec) == NULL) { sec->used_by_bfd = ((PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata))); if (sec->used_by_bfd == NULL) goto error_return; } coff_section_data (abfd, sec)->relocs = internal_relocs; coff_section_data (abfd, sec)->keep_relocs = true; free_relocs = NULL; coff_section_data (abfd, sec)->contents = contents; coff_section_data (abfd, sec)->keep_contents = true; free_contents = NULL; obj_coff_keep_syms (abfd) = true; } } 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 coff_link_input_bfd. */ if (coff_section_data (abfd, sec) == NULL) { sec->used_by_bfd = ((PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata))); if (sec->used_by_bfd == NULL) goto error_return; coff_section_data (abfd, sec)->relocs = NULL; } coff_section_data (abfd, sec)->contents = contents; } } return true; error_return: if (free_relocs != NULL) free (free_relocs); if (free_contents != NULL) free (free_contents); return false;}/* Delete some bytes from a section while relaxing. */static booleansh_relax_delete_bytes (abfd, sec, addr, count) bfd *abfd; asection *sec; bfd_vma addr; int count;{ bfd_byte *contents; struct internal_reloc *irel, *irelend; struct internal_reloc *irelalign; bfd_vma toaddr; bfd_byte *esym, *esymend; bfd_size_type symesz; struct coff_link_hash_entry **sym_hash; asection *o; contents = coff_section_data (abfd, sec)->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 = coff_section_data (abfd, sec)->relocs; irelend = irel + sec->reloc_count; for (; irel < irelend; irel++) { if (irel->r_type == R_SH_ALIGN && irel->r_vaddr - sec->vma > addr && count < (1 << irel->r_offset)) { irelalign = irel; toaddr = irel->r_vaddr - sec->vma; 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 = coff_section_data (abfd, sec)->relocs; irel < irelend; irel++) { bfd_vma nraddr, stop; bfd_vma start = 0; int insn = 0; struct internal_syment sym; int off, adjust, oinsn; bfd_signed_vma voff = 0; boolean overflow; /* Get the new reloc address. */ nraddr = irel->r_vaddr - sec->vma; if ((irel->r_vaddr - sec->vma > addr && irel->r_vaddr - sec->vma < toaddr) || (irel->r_type == R_SH_ALIGN && irel->r_vaddr - sec->vma == 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_vaddr - sec->vma >= addr && irel->r_vaddr - sec->vma < addr + count && irel->r_type != R_SH_ALIGN && irel->r_type != R_SH_CODE && irel->r_type != R_SH_DATA && irel->r_type != R_SH_LABEL) irel->r_type = R_SH_UNUSED; /* If this is a PC relative reloc, see if the range it covers includes the bytes we have deleted. */ switch (irel->r_type) { default: break; case R_SH_PCDISP8BY2: case R_SH_PCDISP: case R_SH_PCRELIMM8BY2: case R_SH_PCRELIMM8BY4: start = irel->r_vaddr - sec->vma; insn = bfd_get_16 (abfd, contents + nraddr); break; } switch (irel->r_type) { default: start = stop = addr; break; case R_SH_IMM32:#ifdef COFF_WITH_PE case R_SH_IMM32CE: case R_SH_IMAGEBASE:#endif /* 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. */ bfd_coff_swap_sym_in (abfd, ((bfd_byte *) obj_coff_external_syms (abfd) + (irel->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; val = bfd_get_32 (abfd, contents + nraddr); val += sym.n_value; if (val > addr && val < toaddr) bfd_put_32 (abfd, val - count, contents + nraddr); } start = stop = addr; break; case R_SH_PCDISP8BY2: off = insn & 0xff; if (off & 0x80) off -= 0x100; stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); break; case R_SH_PCDISP: bfd_coff_swap_sym_in (abfd, ((bfd_byte *) obj_coff_external_syms (abfd) + (irel->r_symndx * bfd_coff_symesz (abfd))), &sym); if (sym.n_sclass == C_EXT) start = stop = addr; else { off = insn & 0xfff; if (off & 0x800) off -= 0x1000; stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?