📄 elf32-arm.h
字号:
return bfd_reloc_ok; case R_ARM_ABS12: /* Support ldr and str instruction for the arm */ /* Also thumb b (unconditional branch). ??? Really? */ value += addend; if ((long) value > 0x7ff || (long) value < -0x800) return bfd_reloc_overflow; value |= (bfd_get_32 (input_bfd, hit_data) & 0xfffff000); bfd_put_32 (input_bfd, value, hit_data); return bfd_reloc_ok; case R_ARM_THM_ABS5: /* Support ldr and str instructions for the thumb. */#ifdef USE_REL /* Need to refetch addend. */ addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask; /* ??? Need to determine shift amount from operand size. */ addend >>= howto->rightshift;#endif value += addend; /* ??? Isn't value unsigned? */ if ((long) value > 0x1f || (long) value < -0x10) return bfd_reloc_overflow; /* ??? Value needs to be properly shifted into place first. */ value |= bfd_get_16 (input_bfd, hit_data) & 0xf83f; bfd_put_16 (input_bfd, value, hit_data); return bfd_reloc_ok;#ifndef OLD_ARM_ABI case R_ARM_THM_XPC22:#endif case R_ARM_THM_PC22: /* Thumb BL (branch long instruction). */ { bfd_vma relocation; boolean overflow = false; bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data); bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2); bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; bfd_signed_vma reloc_signed_min = ~ reloc_signed_max; bfd_vma check; bfd_signed_vma signed_check;#ifdef USE_REL /* Need to refetch the addend and squish the two 11 bit pieces together. */ { bfd_vma upper = upper_insn & 0x7ff; bfd_vma lower = lower_insn & 0x7ff; upper = (upper ^ 0x400) - 0x400; /* Sign extend. */ addend = (upper << 12) | (lower << 1); signed_addend = addend; }#endif#ifndef OLD_ARM_ABI if (r_type == R_ARM_THM_XPC22) { /* Check for Thumb to Thumb call. */ /* FIXME: Should we translate the instruction into a BL instruction instead ? */ if (sym_flags == STT_ARM_TFUNC) _bfd_error_handler (_("\%s: Warning: Thumb BLX instruction targets thumb function '%s'."), bfd_get_filename (input_bfd), h ? h->root.root.string : "(local)"); } else#endif { /* If it is not a call to Thumb, assume call to Arm. If it is a call relative to a section name, then it is not a function call at all, but rather a long jump. */ if (sym_flags != STT_ARM_TFUNC && sym_flags != STT_SECTION) { if (elf32_thumb_to_arm_stub (info, sym_name, input_bfd, output_bfd, input_section, hit_data, sym_sec, rel->r_offset, signed_addend, value)) return bfd_reloc_ok; else return bfd_reloc_dangerous; } } relocation = value + signed_addend; relocation -= (input_section->output_section->vma + input_section->output_offset + rel->r_offset); if (! globals->no_pipeline_knowledge) { Elf_Internal_Ehdr * i_ehdrp; /* Elf file header, internal form. */ i_ehdrp = elf_elfheader (input_bfd); /* Previous versions of this code also used to add in the pipline 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 ( strcmp (bfd_get_target (input_bfd), "elf32-littlearm-oabi") == 0 || strcmp (bfd_get_target (input_bfd), "elf32-bigarm-oabi") == 0 || i_ehdrp->e_ident[EI_OSABI] == 0) relocation += 4; } check = relocation >> howto->rightshift; /* If this is a signed value, the rightshift just dropped leading 1 bits (assuming twos complement). */ if ((bfd_signed_vma) relocation >= 0) signed_check = check; else signed_check = check | ~((bfd_vma) -1 >> howto->rightshift); /* Assumes two's complement. */ if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) overflow = true; /* Put RELOCATION back into the insn. */ upper_insn = (upper_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 12) & 0x7ff); lower_insn = (lower_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 1) & 0x7ff);#ifndef OLD_ARM_ABI if (r_type == R_ARM_THM_XPC22 && ((lower_insn & 0x1800) == 0x0800)) /* Remove bit zero of the adjusted offset. Bit zero can only be set if the upper insn is at a half-word boundary, since the destination address, an ARM instruction, must always be on a word boundary. The semantics of the BLX (1) instruction, however, are that bit zero in the offset must always be zero, and the corresponding bit one in the target address will be set from bit one of the source address. */ lower_insn &= ~1;#endif /* Put the relocated value back in the object file: */ bfd_put_16 (input_bfd, upper_insn, hit_data); bfd_put_16 (input_bfd, lower_insn, hit_data + 2); return (overflow ? bfd_reloc_overflow : bfd_reloc_ok); } break; case R_ARM_GNU_VTINHERIT: case R_ARM_GNU_VTENTRY: return bfd_reloc_ok; case R_ARM_COPY: return bfd_reloc_notsupported; case R_ARM_GLOB_DAT: return bfd_reloc_notsupported; case R_ARM_JUMP_SLOT: return bfd_reloc_notsupported; case R_ARM_RELATIVE: return bfd_reloc_notsupported; case R_ARM_GOTOFF: /* Relocation is relative to the start of the global offset table. */ BFD_ASSERT (sgot != NULL); if (sgot == NULL) return bfd_reloc_notsupported; /* Note that sgot->output_offset is not involved in this calculation. We always want the start of .got. If we define _GLOBAL_OFFSET_TABLE in a different way, as is permitted by the ABI, we might have to change this calculation. */ value -= sgot->output_section->vma; return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, value, (bfd_vma) 0); case R_ARM_GOTPC: /* Use global offset table as symbol value. */ BFD_ASSERT (sgot != NULL); if (sgot == NULL) return bfd_reloc_notsupported; value = sgot->output_section->vma; return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, value, (bfd_vma) 0); case R_ARM_GOT32: /* Relocation is to the entry for this symbol in the global offset table. */ if (sgot == NULL) return bfd_reloc_notsupported; if (h != NULL) { bfd_vma off; off = h->got.offset; BFD_ASSERT (off != (bfd_vma) -1); if (!elf_hash_table (info)->dynamic_sections_created || (info->shared && (info->symbolic || h->dynindx == -1) && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) { /* This is actually a static link, or it is a -Bsymbolic link and the symbol is defined locally. We must initialize this entry in the global offset table. Since the offset must always be a multiple of 4, we use the least significant bit to record whether we have initialized it already. When doing a dynamic link, we create a .rel.got relocation entry to initialize the value. This is done in the finish_dynamic_symbol routine. */ if ((off & 1) != 0) off &= ~1; else { bfd_put_32 (output_bfd, value, sgot->contents + off); h->got.offset |= 1; } } value = sgot->output_offset + off; } else { bfd_vma off; BFD_ASSERT (local_got_offsets != NULL && local_got_offsets[r_symndx] != (bfd_vma) -1); off = local_got_offsets[r_symndx]; /* The offset must always be a multiple of 4. We use the least significant bit to record whether we have already generated the necessary reloc. */ if ((off & 1) != 0) off &= ~1; else { bfd_put_32 (output_bfd, value, sgot->contents + off); if (info->shared) { asection * srelgot; Elf_Internal_Rel outrel; srelgot = bfd_get_section_by_name (dynobj, ".rel.got"); BFD_ASSERT (srelgot != NULL); outrel.r_offset = (sgot->output_section->vma + sgot->output_offset + off); outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE); bfd_elf32_swap_reloc_out (output_bfd, &outrel, (((Elf32_External_Rel *) srelgot->contents) + srelgot->reloc_count)); ++srelgot->reloc_count; } local_got_offsets[r_symndx] |= 1; } value = sgot->output_offset + off; } return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, value, (bfd_vma) 0); case R_ARM_PLT32: /* Relocation is to the entry for this symbol in the procedure linkage table. */ /* Resolve a PLT32 reloc against a local symbol directly, without using the procedure linkage table. */ if (h == NULL) return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, value, (bfd_vma) 0); if (h->plt.offset == (bfd_vma) -1) /* We didn't make a PLT entry for this symbol. This happens when statically linking PIC code, or when using -Bsymbolic. */ return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, value, (bfd_vma) 0); BFD_ASSERT(splt != NULL); if (splt == NULL) return bfd_reloc_notsupported; value = (splt->output_section->vma + splt->output_offset + h->plt.offset); return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, value, (bfd_vma) 0); case R_ARM_SBREL32: return bfd_reloc_notsupported; case R_ARM_AMP_VCALL9: return bfd_reloc_notsupported; case R_ARM_RSBREL32: return bfd_reloc_notsupported; case R_ARM_THM_RPC22: return bfd_reloc_notsupported; case R_ARM_RREL32: return bfd_reloc_notsupported; case R_ARM_RABS32: return bfd_reloc_notsupported; case R_ARM_RPC24: return bfd_reloc_notsupported; case R_ARM_RBASE: return bfd_reloc_notsupported; default: return bfd_reloc_notsupported; }}#ifdef USE_REL/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. */static voidarm_add_to_rel (abfd, address, howto, increment) bfd * abfd; bfd_byte * address; reloc_howto_type * howto; bfd_signed_vma increment;{ bfd_signed_vma addend; if (howto->type == R_ARM_THM_PC22) { int upper_insn, lower_insn; int upper, lower; upper_insn = bfd_get_16 (abfd, address); lower_insn = bfd_get_16 (abfd, address + 2); upper = upper_insn & 0x7ff; lower = lower_insn & 0x7ff; addend = (upper << 12) | (lower << 1); addend += increment; addend >>= 1; upper_insn = (upper_insn & 0xf800) | ((addend >> 11) & 0x7ff); lower_insn = (lower_insn & 0xf800) | (addend & 0x7ff); bfd_put_16 (abfd, upper_insn, address); bfd_put_16 (abfd, lower_insn, address + 2); } else { bfd_vma contents; contents = bfd_get_32 (abfd, address); /* Get the (signed) value from the instruction. */ addend = contents & howto->src_mask; if (addend & ((howto->src_mask + 1) >> 1)) { bfd_signed_vma mask; mask = -1; mask &= ~ howto->src_mask; addend |= mask; } /* Add in the increment, (which is a byte value). */ switch (howto->type) { default: addend += increment; break; case R_ARM_PC24: addend <<= howto->size; addend += increment; /* Should we check for overflow here ? */ /* Drop any undesired bits. */ addend >>= howto->rightshift; break; } contents = (contents & ~ howto->dst_mask) | (addend & howto->dst_mask); bfd_put_32 (abfd, contents, address); }}#endif /* USE_REL *//* Relocate an ARM ELF section. */static booleanelf32_arm_relocate_section (output_bfd, info, input_bfd, input_section, contents, relocs, local_syms, local_sections) bfd * output_bfd; struct bfd_link_info * info; bfd * input_bfd; asection * input_section; bfd_byte * contents; Elf_Internal_Rela * relocs; Elf_Internal_Sym * local_syms; asection ** local_sections;{ Elf_Internal_Shdr * symtab_hdr; struct elf_link_hash_entry ** sym_hashes; Elf_Internal_Rela * rel; Elf_Internal_Rela * relend; const char * name; symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; sym_hashes = elf_sym_hashes (input_bfd); rel = relocs; relend = relocs + input_section->reloc_count; for (; rel < relend; rel++) { int r_type; reloc_howto_type * howto; unsigned long r_symndx; Elf_Internal_Sym * sym;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -