📄 elf32-m32r.c
字号:
if (!((*info->callbacks->warning) (info, errmsg, name, input_bfd, input_section, offset))) return false; break; } } } return ret;}#if 0 /* relaxing not supported yet *//* This function handles relaxing for the m32r. Relaxing on the m32r is tricky because of instruction alignment requirements (4 byte instructions must be aligned on 4 byte boundaries). The following relaxing opportunities are handled: seth/add3/jl -> bl24 or bl8 seth/add3 -> ld24 It would be nice to handle bl24 -> bl8 but given: - 4 byte insns must be on 4 byte boundaries - branch instructions only branch to insns on 4 byte boundaries this isn't much of a win because the insn in the 2 "deleted" bytes must become a nop. With some complexity some real relaxation could be done but the frequency just wouldn't make it worth it; it's better to try to do all the code compaction one can elsewhere. When the chip supports parallel 16 bit insns, things may change.*/static booleanm32r_elf_relax_section (abfd, sec, link_info, again) bfd *abfd; asection *sec; struct bfd_link_info *link_info; boolean *again;{ Elf_Internal_Shdr *symtab_hdr; /* The Rela structures are used here because that's what _bfd_elf32_link_read_relocs uses [for convenience - it sets the addend field to 0]. */ Elf_Internal_Rela *internal_relocs; Elf_Internal_Rela *free_relocs = NULL; Elf_Internal_Rela *irel, *irelend; bfd_byte *contents = NULL; bfd_byte *free_contents = NULL; Elf32_External_Sym *extsyms = NULL; Elf32_External_Sym *free_extsyms = NULL; /* Assume nothing changes. */ *again = false; /* We don't have to do anything for a relocateable link, if this section does not have relocs, or if this is not a code section. */ if (link_info->relocateable || (sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0 || 0 /* FIXME: check SHF_M32R_CAN_RELAX */) return true; /* If this is the first time we have been called for this section, initialize the cooked size. */ if (sec->_cooked_size == 0) sec->_cooked_size = sec->_raw_size; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; /* Get a copy of the native relocations. */ internal_relocs = (_bfd_elf32_link_read_relocs (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL, link_info->keep_memory)); if (internal_relocs == NULL) goto error_return; if (! link_info->keep_memory) free_relocs = internal_relocs; /* Walk through them looking for relaxing opportunities. */ irelend = internal_relocs + sec->reloc_count; for (irel = internal_relocs; irel < irelend; irel++) { bfd_vma symval; /* If this isn't something that can be relaxed, then ignore this reloc. */ if (ELF32_R_TYPE (irel->r_info) != (int) R_M32R_HI16_SLO) continue; /* Get the section contents if we haven't done so already. */ if (contents == NULL) { /* Get cached copy if it exists. */ if (elf_section_data (sec)->this_hdr.contents != NULL) contents = elf_section_data (sec)->this_hdr.contents; else { /* Go get them off disk. */ 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; } } /* Read this BFD's symbols if we haven't done so already. */ if (extsyms == NULL) { /* Get cached copy if it exists. */ if (symtab_hdr->contents != NULL) extsyms = (Elf32_External_Sym *) symtab_hdr->contents; else { /* Go get them off disk. */ extsyms = ((Elf32_External_Sym *) bfd_malloc (symtab_hdr->sh_size)); if (extsyms == NULL) goto error_return; free_extsyms = extsyms; if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0 || (bfd_read (extsyms, 1, symtab_hdr->sh_size, abfd) != symtab_hdr->sh_size)) goto error_return; } } /* Get the value of the symbol referred to by the reloc. */ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) { Elf_Internal_Sym isym; asection *sym_sec; /* A local symbol. */ bfd_elf32_swap_symbol_in (abfd, extsyms + ELF32_R_SYM (irel->r_info), &isym); sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx); symval = (isym.st_value + sym_sec->output_section->vma + sym_sec->output_offset); } else { unsigned long indx; struct elf_link_hash_entry *h; /* An external symbol. */ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; h = elf_sym_hashes (abfd)[indx]; 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); } /* 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. */ /* Try to change a seth/add3/jl subroutine call to bl24 or bl8. This sequence is generated by the compiler when compiling in 32 bit mode. Also look for seth/add3 -> ld24. */ if (ELF32_R_TYPE (irel->r_info) == (int) R_M32R_HI16_SLO) { Elf_Internal_Rela *nrel; bfd_vma pc = (sec->output_section->vma + sec->output_offset + irel->r_offset); bfd_signed_vma pcrel_value = symval - pc; unsigned int code,reg; int addend,nop_p,bl8_p,to_delete; /* The tests are ordered so that we get out as quickly as possible if this isn't something we can relax, taking into account that we are looking for two separate possibilities (jl/ld24). */ /* Do nothing if no room in the section for this to be what we're looking for. */ if (irel->r_offset > sec->_cooked_size - 8) continue; /* Make sure the next relocation applies to the next instruction and that it's the add3's reloc. */ nrel = irel + 1; if (nrel == irelend || irel->r_offset + 4 != nrel->r_offset || ELF32_R_TYPE (nrel->r_info) != (int) R_M32R_LO16) continue; /* See if the instructions are seth/add3. */ /* FIXME: This is where macros from cgen can come in. */ code = bfd_get_16 (abfd, contents + irel->r_offset + 0); if ((code & 0xf0ff) != 0xd0c0) continue; /* not seth rN,foo */ reg = (code & 0x0f00) >> 8; code = bfd_get_16 (abfd, contents + irel->r_offset + 4); if (code != (0x80a0 | reg | (reg << 8))) continue; /* not add3 rN,rN,foo */ /* At this point we've confirmed we have seth/add3. Now check whether the next insn is a jl, in which case try to change this to bl24 or bl8. */ /* Ensure the branch target is in range. The bl24 instruction has a 24 bit operand which is the target address right shifted by 2, giving a signed range of 26 bits. Note that 4 bytes are added to the high value because the target will be at least 4 bytes closer if we can relax. It'll actually be 4 or 8 bytes closer, but we don't know which just yet and the difference isn't significant enough to worry about. */#ifndef USE_REL /* put in for learning purposes */ pcrel_value += irel->r_addend;#else addend = bfd_get_signed_16 (abfd, contents + irel->r_offset + 2); pcrel_value += addend;#endif if (pcrel_value >= -(1 << 25) && pcrel_value < (1 << 25) + 4 /* Do nothing if no room in the section for this to be what we're looking for. */ && (irel->r_offset <= sec->_cooked_size - 12) /* Ensure the next insn is "jl rN". */ && ((code = bfd_get_16 (abfd, contents + irel->r_offset + 8)), code != (0x1ec0 | reg))) { /* We can relax to bl24/bl8. */ /* See if there's a nop following the jl. Also see if we can use a bl8 insn. */ code = bfd_get_16 (abfd, contents + irel->r_offset + 10); nop_p = (code & 0x7fff) == NOP_INSN; bl8_p = pcrel_value >= -0x200 && pcrel_value < 0x200; if (bl8_p) { /* Change "seth rN,foo" to "bl8 foo || nop". We OR in CODE just in case it's not a nop (technically, CODE currently must be a nop, but for cleanness we allow it to be anything). */#ifndef USE_REL /* put in for learning purposes */ code = 0x7e000000 | MAKE_PARALLEL (code);#else code = (0x7e000000 + (((addend >> 2) & 0xff) << 16)) | MAKE_PARALLEL (code);#endif to_delete = 8; } else { /* Change the seth rN,foo to a bl24 foo. */#ifndef USE_REL /* put in for learning purposes */ code = 0xfe000000;#else code = 0xfe000000 + ((addend >> 2) & 0xffffff);#endif to_delete = nop_p ? 8 : 4; } bfd_put_32 (abfd, code, contents + irel->r_offset); /* Set the new reloc type. */ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (nrel->r_info), bl8_p ? R_M32R_10_PCREL : R_M32R_26_PCREL); /* Delete the add3 reloc by making it a null reloc. */ nrel->r_info = ELF32_R_INFO (ELF32_R_SYM (nrel->r_info), R_M32R_NONE); } else if (addend >= 0 && symval + addend <= 0xffffff) { /* We can relax to ld24. */ code = 0xe0000000 | (reg << 24) | (addend & 0xffffff); bfd_put_32 (abfd, code, contents + irel->r_offset); to_delete = 4; /* Tell the following code a nop filler isn't needed. */ nop_p = 1; } else { /* Can't do anything here. */ continue; } /* Note that we've changed the relocs, section contents, etc. */ 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; /* Delete TO_DELETE bytes of data. */ if (!m32r_elf_relax_delete_bytes (abfd, sec, irel->r_offset + 4, to_delete)) goto error_return; /* Now that the following bytes have been moved into place, see if we need to replace the jl with a nop. This happens when we had to use a bl24 insn and the insn following the jl isn't a nop. Technically, this situation can't happen (since the insn can never be executed) but to be clean we do this. When the chip supports parallel 16 bit insns things may change. We don't need to do this in the case of relaxing to ld24, and the above code sets nop_p so this isn't done. */ if (! nop_p && to_delete == 4) bfd_put_16 (abfd, NOP_INSN, contents + irel->r_offset + 4); /* That will change things, so we should relax again. Note that this is not required, and it may be slow. */ *again = true; continue; } /* loop to try the next reloc */ } 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. */static booleanm32r_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; 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; /* Actually delete the bytes. */ memmove (contents + addr, contents + addr + count, toaddr - addr - count); sec->_cooked_size -= count; /* Adjust all the relocs. */ for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -