?? elf32-arm.h
字號:
/* Now go back and fix up the original BL insn to point to here. */ ret_offset = s->output_offset + my_offset - (input_section->output_offset + offset + addend) - 8; tmp = bfd_get_32 (input_bfd, hit_data - input_section->vma); bfd_put_32 (output_bfd, insert_thumb_branch (tmp, ret_offset), hit_data - input_section->vma); return true;}/* Arm code calling a Thumb function. */static intelf32_arm_to_thumb_stub (info, name, input_bfd, output_bfd, input_section, hit_data, sym_sec, offset, addend, val) struct bfd_link_info * info; const char * name; bfd * input_bfd; bfd * output_bfd; asection * input_section; bfd_byte * hit_data; asection * sym_sec; bfd_vma offset; bfd_signed_vma addend; bfd_vma val;{ unsigned long int tmp; long int my_offset; asection * s; long int ret_offset; struct elf_link_hash_entry * myh; struct elf32_arm_link_hash_table * globals; myh = find_arm_glue (info, name, input_bfd); if (myh == NULL) return false; globals = elf32_arm_hash_table (info); BFD_ASSERT (globals != NULL); BFD_ASSERT (globals->bfd_of_glue_owner != NULL); my_offset = myh->root.u.def.value; s = bfd_get_section_by_name (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME); BFD_ASSERT (s != NULL); BFD_ASSERT (s->contents != NULL); BFD_ASSERT (s->output_section != NULL); if ((my_offset & 0x01) == 0x01) { if (sym_sec != NULL && sym_sec->owner != NULL && !INTERWORK_FLAG (sym_sec->owner)) { _bfd_error_handler (_("%s(%s): warning: interworking not enabled."), bfd_get_filename (sym_sec->owner), name); _bfd_error_handler (_(" first occurrence: %s: arm call to thumb"), bfd_get_filename (input_bfd)); } --my_offset; myh->root.u.def.value = my_offset; bfd_put_32 (output_bfd, a2t1_ldr_insn, s->contents + my_offset); bfd_put_32 (output_bfd, a2t2_bx_r12_insn, s->contents + my_offset + 4); /* It's a thumb address. Add the low order bit. */ bfd_put_32 (output_bfd, val | a2t3_func_addr_insn, s->contents + my_offset + 8); } BFD_ASSERT (my_offset <= globals->arm_glue_size); tmp = bfd_get_32 (input_bfd, hit_data); tmp = tmp & 0xFF000000; /* Somehow these are both 4 too far, so subtract 8. */ ret_offset = s->output_offset + my_offset + s->output_section->vma - (input_section->output_offset + input_section->output_section->vma + offset + addend) - 8; tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF); bfd_put_32 (output_bfd, tmp, hit_data - input_section->vma); return true;}/* Perform a relocation as part of a final link. */static bfd_reloc_status_typeelf32_arm_final_link_relocate (howto, input_bfd, output_bfd, input_section, contents, rel, value, info, sym_sec, sym_name, sym_flags, h) reloc_howto_type * howto; bfd * input_bfd; bfd * output_bfd; asection * input_section; bfd_byte * contents; Elf_Internal_Rela * rel; bfd_vma value; struct bfd_link_info * info; asection * sym_sec; const char * sym_name; unsigned char sym_flags; struct elf_link_hash_entry * h;{ unsigned long r_type = howto->type; unsigned long r_symndx; bfd_byte * hit_data = contents + rel->r_offset; bfd * dynobj = NULL; Elf_Internal_Shdr * symtab_hdr; struct elf_link_hash_entry ** sym_hashes; bfd_vma * local_got_offsets; asection * sgot = NULL; asection * splt = NULL; asection * sreloc = NULL; bfd_vma addend; bfd_signed_vma signed_addend; struct elf32_arm_link_hash_table * globals; /* If the start address has been set, then set the EF_ARM_HASENTRY flag. Setting this more than once is redundant, but the cost is not too high, and it keeps the code simple. The test is done here, rather than somewhere else, because the start address is only set just before the final link commences. Note - if the user deliberately sets a start address of 0, the flag will not be set. */ if (bfd_get_start_address (output_bfd) != 0) elf_elfheader (output_bfd)->e_flags |= EF_ARM_HASENTRY; globals = elf32_arm_hash_table (info); dynobj = elf_hash_table (info)->dynobj; if (dynobj) { sgot = bfd_get_section_by_name (dynobj, ".got"); splt = bfd_get_section_by_name (dynobj, ".plt"); } symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; sym_hashes = elf_sym_hashes (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd); r_symndx = ELF32_R_SYM (rel->r_info);#ifdef USE_REL addend = bfd_get_32 (input_bfd, hit_data) & howto->src_mask; if (addend & ((howto->src_mask + 1) >> 1)) { signed_addend = -1; signed_addend &= ~ howto->src_mask; signed_addend |= addend; } else signed_addend = addend;#else addend = signed_addend = rel->r_addend;#endif switch (r_type) { case R_ARM_NONE: return bfd_reloc_ok; case R_ARM_PC24: case R_ARM_ABS32: case R_ARM_REL32:#ifndef OLD_ARM_ABI case R_ARM_XPC25:#endif /* When generating a shared object, these relocations are copied into the output file to be resolved at run time. */ if (info->shared && (r_type != R_ARM_PC24 || (h != NULL && h->dynindx != -1 && (! info->symbolic || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)))) { Elf_Internal_Rel outrel; boolean skip, relocate; if (sreloc == NULL) { const char * name; name = (bfd_elf_string_from_elf_section (input_bfd, elf_elfheader (input_bfd)->e_shstrndx, elf_section_data (input_section)->rel_hdr.sh_name)); if (name == NULL) return bfd_reloc_notsupported; BFD_ASSERT (strncmp (name, ".rel", 4) == 0 && strcmp (bfd_get_section_name (input_bfd, input_section), name + 4) == 0); sreloc = bfd_get_section_by_name (dynobj, name); BFD_ASSERT (sreloc != NULL); } skip = false; if (elf_section_data (input_section)->stab_info == NULL) outrel.r_offset = rel->r_offset; else { bfd_vma off; off = (_bfd_stab_section_offset (output_bfd, &elf_hash_table (info)->stab_info, input_section, & elf_section_data (input_section)->stab_info, rel->r_offset)); if (off == (bfd_vma) -1) skip = true; outrel.r_offset = off; } outrel.r_offset += (input_section->output_section->vma + input_section->output_offset); if (skip) { memset (&outrel, 0, sizeof outrel); relocate = false; } else if (r_type == R_ARM_PC24) { BFD_ASSERT (h != NULL && h->dynindx != -1); if ((input_section->flags & SEC_ALLOC) != 0) relocate = false; else relocate = true; outrel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_PC24); } else { if (h == NULL || ((info->symbolic || h->dynindx == -1) && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)) { relocate = true; outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE); } else { BFD_ASSERT (h->dynindx != -1); if ((input_section->flags & SEC_ALLOC) != 0) relocate = false; else relocate = true; outrel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_ABS32); } } bfd_elf32_swap_reloc_out (output_bfd, &outrel, (((Elf32_External_Rel *) sreloc->contents) + sreloc->reloc_count)); ++sreloc->reloc_count; /* If this reloc is against an external symbol, we do not want to fiddle with the addend. Otherwise, we need to include the symbol value so that it becomes an addend for the dynamic reloc. */ if (! relocate) return bfd_reloc_ok; return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, value, (bfd_vma) 0); } else switch (r_type) {#ifndef OLD_ARM_ABI case R_ARM_XPC25: /* Arm BLX instruction. */#endif case R_ARM_PC24: /* Arm B/BL instruction */#ifndef OLD_ARM_ABI if (r_type == R_ARM_XPC25) { /* Check for Arm calling Arm function. */ /* FIXME: Should we translate the instruction into a BL instruction instead ? */ if (sym_flags != STT_ARM_TFUNC) _bfd_error_handler (_("\%s: Warning: Arm BLX instruction targets Arm function '%s'."), bfd_get_filename (input_bfd), h ? h->root.root.string : "(local)"); } else#endif { /* Check for Arm calling Thumb function. */ if (sym_flags == STT_ARM_TFUNC) { elf32_arm_to_thumb_stub (info, sym_name, input_bfd, output_bfd, input_section, hit_data, sym_sec, rel->r_offset, signed_addend, value); return bfd_reloc_ok; } } if ( strcmp (bfd_get_target (input_bfd), "elf32-littlearm-oabi") == 0 || strcmp (bfd_get_target (input_bfd), "elf32-bigarm-oabi") == 0) { /* The old way of doing things. Trearing the addend as a byte sized field and adding in the pipeline offset. */ value -= (input_section->output_section->vma + input_section->output_offset); value -= rel->r_offset; value += addend; if (! globals->no_pipeline_knowledge) value -= 8; } else { /* The ARM ELF ABI says that this reloc is computed as: S - P + A where: S is the address of the symbol in the relocation. P is address of the instruction being relocated. A is the addend (extracted from the instruction) in bytes. S is held in 'value'. P is the base address of the section containing the instruction plus the offset of the reloc into that section, ie: (input_section->output_section->vma + input_section->output_offset + rel->r_offset). A is the addend, converted into bytes, ie: (signed_addend * 4) Note: None of these operations have knowledge of the pipeline size of the processor, thus it is up to the assembler to encode this information into the addend. */ value -= (input_section->output_section->vma + input_section->output_offset); value -= rel->r_offset; value += (signed_addend << howto->size); /* Previous versions of this code also used to add in the pipeline offset here. This is wrong because the linker is not supposed to know about such things, and one day it might change. In order to support old binaries that need the old behaviour however, so we attempt to detect which ABI was used to create the reloc. */ if (! globals->no_pipeline_knowledge) { Elf_Internal_Ehdr * i_ehdrp; /* Elf file header, internal form */ i_ehdrp = elf_elfheader (input_bfd); if (i_ehdrp->e_ident[EI_OSABI] == 0) value -= 8; } } signed_addend = value; signed_addend >>= howto->rightshift; /* It is not an error for an undefined weak reference to be out of range. Any program that branches to such a symbol is going to crash anyway, so there is no point worrying about getting the destination exactly right. */ if (! h || h->root.type != bfd_link_hash_undefweak) { /* Perform a signed range check. */ if ( signed_addend > ((bfd_signed_vma) (howto->dst_mask >> 1)) || signed_addend < - ((bfd_signed_vma) ((howto->dst_mask + 1) >> 1))) return bfd_reloc_overflow; }#ifndef OLD_ARM_ABI /* If necessary set the H bit in the BLX instruction. */ if (r_type == R_ARM_XPC25 && ((value & 2) == 2)) value = (signed_addend & howto->dst_mask) | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask)) | (1 << 24); else#endif value = (signed_addend & howto->dst_mask) | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask)); break; case R_ARM_ABS32: value += addend; if (sym_flags == STT_ARM_TFUNC) value |= 1; break; case R_ARM_REL32: value -= (input_section->output_section->vma + input_section->output_offset); value += addend; break; } bfd_put_32 (input_bfd, value, hit_data); return bfd_reloc_ok; case R_ARM_ABS8: value += addend; if ((long) value > 0x7f || (long) value < -0x80) return bfd_reloc_overflow; bfd_put_8 (input_bfd, value, hit_data); return bfd_reloc_ok; case R_ARM_ABS16: value += addend; if ((long) value > 0x7fff || (long) value < -0x8000) return bfd_reloc_overflow; bfd_put_16 (input_bfd, value, hit_data);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -