📄 elf-m10300.c
字号:
free_relocs = NULL; } /* Cache or free any memory we allocated for the contents. */ 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 (section)->this_hdr.contents = contents; } free_contents = NULL; } } /* Cache or free any memory we allocated for the symbols. */ 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; } } } /* (Re)initialize for the basic instruction shortening/relaxing pass. */ contents = NULL; extsyms = NULL; internal_relocs = NULL; free_relocs = NULL; free_contents = NULL; free_extsyms = NULL; /* 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) 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; struct elf32_mn10300_link_hash_entry *h = NULL; /* If this isn't something that can be relaxed, then ignore this reloc. */ if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_NONE || ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_8 || ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_MAX) 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 = NULL; const char *sym_name; char *new_name; /* A local symbol. */ bfd_elf32_swap_symbol_in (abfd, extsyms + ELF32_R_SYM (irel->r_info), &isym); if (isym.st_shndx == SHN_UNDEF) sym_sec = bfd_und_section_ptr; else if (isym.st_shndx > 0 && isym.st_shndx < SHN_LORESERVE) sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx); else if (isym.st_shndx == SHN_ABS) sym_sec = bfd_abs_section_ptr; else if (isym.st_shndx == SHN_COMMON) sym_sec = bfd_com_section_ptr; else abort (); symval = (isym.st_value + sym_sec->output_section->vma + sym_sec->output_offset); sym_name = bfd_elf_string_from_elf_section (abfd, symtab_hdr->sh_link, isym.st_name); /* Tack on an ID so we can uniquely identify this local symbol in the global hash table. */ new_name = bfd_malloc (strlen (sym_name) + 10); if (new_name == 0) goto error_return; sprintf (new_name, "%s_%08x", sym_name, (int) sym_sec); sym_name = new_name; h = (struct elf32_mn10300_link_hash_entry *) elf_link_hash_lookup (&hash_table->static_hash_table->root, sym_name, false, false, false); free (new_name); } else { unsigned long indx; /* An external symbol. */ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; h = (struct elf32_mn10300_link_hash_entry *) (elf_sym_hashes (abfd)[indx]); BFD_ASSERT (h != NULL); if (h->root.root.type != bfd_link_hash_defined && h->root.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.root.u.def.value + h->root.root.u.def.section->output_section->vma + h->root.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 turn a 32bit pc-relative branch/call into a 16bit pc-relative branch/call, also deal with "call" -> "calls" conversions and insertion of prologue data into "call" instructions. */ if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PCREL32) { bfd_vma value = symval; /* If we've got a "call" instruction that needs to be turned into a "calls" instruction, do so now. It saves a byte. */ if (h && (h->flags & MN10300_CONVERT_CALL_TO_CALLS)) { unsigned char code; /* Get the opcode. */ code = bfd_get_8 (abfd, contents + irel->r_offset - 1); /* Make sure we're working with a "call" instruction! */ if (code == 0xdd) { /* 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; /* Fix the opcode. */ bfd_put_8 (abfd, 0xfc, contents + irel->r_offset - 1); bfd_put_8 (abfd, 0xff, contents + irel->r_offset); /* Fix irel->r_offset and irel->r_addend. */ irel->r_offset += 1; irel->r_addend += 1; /* Delete one byte of data. */ if (!mn10300_elf_relax_delete_bytes (abfd, sec, irel->r_offset + 3, 1)) goto error_return; /* That will change things, so, we should relax again. Note that this is not required, and it may be slow. */ *again = true; } } else if (h) { /* We've got a "call" instruction which needs some data from target function filled in. */ unsigned char code; /* Get the opcode. */ code = bfd_get_8 (abfd, contents + irel->r_offset - 1); /* Insert data from the target function into the "call" instruction if needed. */ if (code == 0xdd) { bfd_put_8 (abfd, h->movm_args, contents + irel->r_offset + 4); bfd_put_8 (abfd, h->stack_size + h->movm_stack_size, contents + irel->r_offset + 5); } } /* Deal with pc-relative gunk. */ value -= (sec->output_section->vma + sec->output_offset); value -= irel->r_offset; value += irel->r_addend; /* See if the value will fit in 16 bits, note the high value is 0x7fff + 2 as the target will be two bytes closer if we are able to relax. */ if ((long) value < 0x8001 && (long) value > -0x8000) { unsigned char code; /* Get the opcode. */ code = bfd_get_8 (abfd, contents + irel->r_offset - 1); if (code != 0xdc && code != 0xdd && code != 0xff) 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; /* Fix the opcode. */ if (code == 0xdc) bfd_put_8 (abfd, 0xcc, contents + irel->r_offset - 1); else if (code == 0xdd) bfd_put_8 (abfd, 0xcd, contents + irel->r_offset - 1); else if (code == 0xff) bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 2); /* Fix the relocation's type. */ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_MN10300_PCREL16); /* Delete two bytes of data. */ if (!mn10300_elf_relax_delete_bytes (abfd, sec, irel->r_offset + 1, 2)) goto error_return; /* That will change things, so, we should relax again. Note that this is not required, and it may be slow. */ *again = true; } } /* Try to turn a 16bit pc-relative branch into a 8bit pc-relative branch. */ if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PCREL16) { bfd_vma value = symval; /* If we've got a "call" instruction that needs to be turned into a "calls" instruction, do so now. It saves a byte. */ if (h && (h->flags & MN10300_CONVERT_CALL_TO_CALLS)) { unsigned char code; /* Get the opcode. */ code = bfd_get_8 (abfd, contents + irel->r_offset - 1); /* Make sure we're working with a "call" instruction! */ if (code == 0xcd) { /* 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; /* Fix the opcode. */ bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 1); bfd_put_8 (abfd, 0xff, contents + irel->r_offset); /* Fix irel->r_offset and irel->r_addend. */ irel->r_offset += 1; irel->r_addend += 1; /* Delete one byte of data. */ if (!mn10300_elf_relax_delete_bytes (abfd, sec, irel->r_offset + 1, 1)) goto error_return; /* That will change things, so, we should relax again. Note that this is not required, and it may be slow. */ *again = true; } } else if (h) { unsigned char code; /* Get the opcode. */ code = bfd_get_8 (abfd, contents + irel->r_offset - 1); /* Insert data from the target function into the "call" instruction if needed. */ if (code == 0xcd) { bfd_put_8 (abfd, h->movm_args, contents + irel->r_offset + 2); bfd_put_8 (abfd, h->stack_size + h->movm_stack_size, contents + irel->r_offset + 3); } } /* Deal with pc-relative gunk. */ value -= (sec->output_section->vma + sec->output_offset); value -= irel->r_offset; value += irel->r_addend; /* See if the value will fit in 8 bits, note the high value is 0x7f + 1 as the target will be one bytes closer if we are able to relax. */ if ((long) value < 0x80 && (long) value > -0x80) { unsigned char code; /* Get the opcode. */ code = bfd_get_8 (abfd, contents + irel->r_offset - 1); if (code != 0xcc) 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; /* Fix the opcode. */ bfd_put_8 (abfd, 0xca, contents + irel->r_offset - 1); /* Fix the relocation's type. */ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_MN10300_PCREL8); /* Delete one byte of data. */ if (!mn10300_elf_relax_delete_bytes (abfd, sec, irel->r_offset + 1, 1)) goto error_return; /* That will change things, so, we should relax again. Note that this is not required, and it may be slow. */ *again = true; } } /* Try to eliminate an unconditional 8 bit pc-relative branch which immediately follows a conditional 8 bit pc-relative branch around the unconditional branch. original: new: bCC lab1 bCC' lab2 bra lab2 lab1: lab1: This happens when the bCC can't reach lab2 at assembly time, but due to other relaxations it can reach at link time. */ if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PCREL8) { Elf_Internal_Rela *nrel; bfd_vma value = symval; unsigned char code; /* Deal with pc-relative gunk. */ value -= (sec->output_section->vma + sec->output_offset); value -= irel->r_offset; value += irel->r_addend;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -