📄 coff-arm.c
字号:
- 8; tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF); bfd_put_32 (output_bfd, tmp, contents + rel->r_vaddr - input_section->vma); done = 1; } }#ifndef ARM_WINCE /* Note: We used to check for ARM_THUMB9 and ARM_THUMB12 */ else if (howto->type == ARM_THUMB23) { if ( h->class == C_EXT || h->class == C_STAT || h->class == C_LABEL) { /* Thumb code calling an ARM function */ asection * s = 0; long int my_offset; unsigned long int tmp; long int ret_offset; struct coff_link_hash_entry * myh; struct coff_arm_link_hash_table * globals; myh = find_thumb_glue (info, name, input_bfd); if (myh == NULL) return false; globals = coff_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, THUMB2ARM_GLUE_SECTION_NAME); BFD_ASSERT (s != NULL); BFD_ASSERT (s->contents != NULL); BFD_ASSERT (s->output_section != NULL); if ((my_offset & 0x01) == 0x01) { if (h_sec->owner != NULL && INTERWORK_SET (h_sec->owner) && ! INTERWORK_FLAG (h_sec->owner) && ! globals->support_old_code) { _bfd_error_handler /* xgettext:c-format */ (_("%s(%s): warning: interworking not enabled."), bfd_get_filename (h_sec->owner), name); _bfd_error_handler /* xgettext:c-format */ (_(" first occurrence: %s: thumb call to arm"), bfd_get_filename (input_bfd)); _bfd_error_handler (_(" consider relinking with --support-old-code enabled")); } -- my_offset; myh->root.u.def.value = my_offset; if (globals->support_old_code) { bfd_put_16 (output_bfd, t2a1_push_insn, s->contents + my_offset); bfd_put_16 (output_bfd, t2a2_ldr_insn, s->contents + my_offset + 2); bfd_put_16 (output_bfd, t2a3_mov_insn, s->contents + my_offset + 4); bfd_put_16 (output_bfd, t2a4_bx_insn, s->contents + my_offset + 6); bfd_put_32 (output_bfd, t2a5_pop_insn, s->contents + my_offset + 8); bfd_put_32 (output_bfd, t2a6_bx_insn, s->contents + my_offset + 12); /* Store the address of the function in the last word of the stub. */ bfd_put_32 (output_bfd, h_val, s->contents + my_offset + 16); if (info->base_file) arm_emit_base_file_entry (info, output_bfd, s, my_offset + 16); } else { bfd_put_16 (output_bfd, t2a1_bx_pc_insn, s->contents + my_offset); bfd_put_16 (output_bfd, t2a2_noop_insn, s->contents + my_offset + 2); ret_offset = ((bfd_signed_vma) h_val) /* Address of destination of the stub */ - ((bfd_signed_vma) (s->output_offset /* Offset from the start of the current section to the start of the stubs. */ + my_offset /* Offset of the start of this stub from the start of the stubs. */ + s->output_section->vma) /* Address of the start of the current section. */ + 4 /* The branch instruction is 4 bytes into the stub. */ + 8); /* ARM branches work from the pc of the instruction + 8. */ bfd_put_32 (output_bfd, t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF), s->contents + my_offset + 4); } } BFD_ASSERT (my_offset <= globals->thumb_glue_size); /* 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 + rel->r_vaddr) -4; tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr - input_section->vma); bfd_put_32 (output_bfd, insert_thumb_branch (tmp, ret_offset), contents + rel->r_vaddr - input_section->vma); done = 1; } }#endif } /* If the relocation type and destination symbol does not fall into one of the above categories, then we can just perform a direct link. */ if (done) rstat = bfd_reloc_ok; else#endif /* THUMBEXTENSION */ if ( h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) { asection *sec; sec = h->root.u.def.section; val = (h->root.u.def.value + sec->output_section->vma + sec->output_offset); } else if (! info->relocateable) { if (! ((*info->callbacks->undefined_symbol) (info, h->root.root.string, input_bfd, input_section, rel->r_vaddr - input_section->vma, true))) return false; } } if (info->base_file) { /* Emit a reloc if the backend thinks it needs it. */ if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto)) arm_emit_base_file_entry (info, output_bfd, input_section, rel->r_vaddr); }#if 1 /* THUMBEXTENSION */ if (done) rstat = bfd_reloc_ok;#ifndef ARM_WINCE /* Only perform this fix during the final link, not a relocatable link. nickc@cygnus.com */ else if (! info->relocateable && howto->type == ARM_THUMB23) { /* This is pretty much a copy of what the default _bfd_final_link_relocate and _bfd_relocate_contents routines do to perform a relocation, with special processing for the split addressing of the Thumb BL instruction. Again, it would probably be simpler adding a ThumbBRANCH23 specific macro expansion into the default code. */ bfd_vma address = rel->r_vaddr - input_section->vma; if (address > input_section->_raw_size) rstat = bfd_reloc_outofrange; else { bfd_vma relocation = val + addend; int size = bfd_get_reloc_size (howto); boolean overflow = false; bfd_byte * location = contents + address; bfd_vma x = bfd_get_32 (input_bfd, location); bfd_vma src_mask = 0x007FFFFE; 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; bfd_vma add; bfd_signed_vma signed_add; BFD_ASSERT (size == 4); /* howto->pc_relative should be TRUE for type 14 BRANCH23. */ relocation -= (input_section->output_section->vma + input_section->output_offset); /* howto->pcrel_offset should be TRUE for type 14 BRANCH23. */ relocation -= address; /* No need to negate the relocation with BRANCH23. */ /* howto->complain_on_overflow == complain_overflow_signed for BRANCH23. */ /* howto->rightshift == 1 */ /* Drop unwanted bits from the value we are relocating to. */ 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 & ~((bfd_vma) - 1 >> howto->rightshift))); /* Get the value from the object file. */ if (bfd_big_endian (input_bfd)) add = (((x) & 0x07ff0000) >> 4) | (((x) & 0x7ff) << 1); else add = ((((x) & 0x7ff) << 12) | (((x) & 0x07ff0000) >> 15)); /* Get the value from the object file with an appropriate sign. The expression involving howto->src_mask isolates the upper bit of src_mask. If that bit is set in the value we are adding, it is negative, and we subtract out that number times two. If src_mask includes the highest possible bit, then we can not get the upper bit, but that does not matter since signed_add needs no adjustment to become negative in that case. */ signed_add = add; if ((add & (((~ src_mask) >> 1) & src_mask)) != 0) signed_add -= (((~ src_mask) >> 1) & src_mask) << 1; /* howto->bitpos == 0 */ /* Add the value from the object file, shifted so that it is a straight number. */ signed_check += signed_add; relocation += signed_add; BFD_ASSERT (howto->complain_on_overflow == complain_overflow_signed); /* Assumes two's complement. */ if ( signed_check > reloc_signed_max || signed_check < reloc_signed_min) overflow = true; /* For the BLX(1) instruction remove bit 0 of the adjusted offset. Bit 0 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 0 in the offset must always be 0, and the corresponding bit 1 in the target address will be set from bit 1 of the source address. */ if ((x & 0x18000000) == 0x08000000) relocation &= ~0x2; /* Put the relocation into the correct bits. */ if (bfd_big_endian (input_bfd)) relocation = (((relocation & 0xffe) >> 1) | ((relocation << 4) & 0x07ff0000)); else relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff)); /* Add the relocation to the correct bits of X. */ x = ((x & ~howto->dst_mask) | relocation); /* Put the relocated value back in the object file. */ bfd_put_32 (input_bfd, x, location); rstat = overflow ? bfd_reloc_overflow : bfd_reloc_ok; } }#endif else#endif /* THUMBEXTENSION */ rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_vaddr - input_section->vma, val, addend);#if 1 /* THUMBEXTENSION */ /* FIXME: Is this the best way to fix up thumb addresses? krk@cygnus.com Probably not, but it works, and if it works it don't need fixing! nickc@cygnus.com */ /* Only perform this fix during the final link, not a relocatable link. nickc@cygnus.com */ if (! info->relocateable && (rel->r_type == ARM_32 || rel->r_type == ARM_RVA32)) { /* Determine if we need to set the bottom bit of a relocated address because the address is the address of a Thumb code symbol. */ int patchit = false; if (h != NULL && ( h->class == C_THUMBSTATFUNC || h->class == C_THUMBEXTFUNC)) { patchit = true; } else if (sym != NULL && sym->n_scnum > N_UNDEF) { /* No hash entry - use the symbol instead. */ if ( sym->n_sclass == C_THUMBSTATFUNC || sym->n_sclass == C_THUMBEXTFUNC) patchit = true; } if (patchit) { bfd_byte * location = contents + rel->r_vaddr - input_section->vma; bfd_vma x = bfd_get_32 (input_bfd, location); bfd_put_32 (input_bfd, x | 1, location); } }#endif /* THUMBEXTENSION */ switch (rstat) { default: abort (); case bfd_reloc_ok: break; case bfd_reloc_outofrange: (*_bfd_error_handler) (_("%s: bad reloc address 0x%lx in section `%s'"), bfd_get_filename (input_bfd), (unsigned long) rel->r_vaddr, bfd_get_section_name (input_bfd, input_section)); return false; case bfd_reloc_overflow: { const char *name; char buf[SYMNMLEN + 1]; if (symndx == -1) name = "*ABS*"; else if (h != NULL) name = h->root.root.string; else { name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); if (name == NULL) return false; } if (! ((*info->callbacks->reloc_overflow) (info, name, howto->name, (bfd_vma) 0, input_bfd, input_section, rel->r_vaddr - input_section->vma))) return false; } } } return true;}#ifndef COFF_IMAGE_WITH_PEbooleanbfd_arm_allocate_interworking_sections (info) struct bfd_link_info * info;{ asection * s; bfd_byte * foo; struct coff_arm_link_hash_table * globals;#if 0 static char test_char = '1';#endif globals = coff_arm_hash_table (info); BFD_ASSERT (globals != NULL); if (globals->arm_glue_size != 0) { BFD_ASSERT (globals->bfd_of_glue_owner != NULL); s = bfd_get_section_by_name (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME); BFD_ASSERT (s != NULL); foo = (bfd_byte *) bfd_alloc (globals->bfd_of_glue_owner, globals->arm_glue_size);#if 0 memset (foo, test_char, globals->arm_glue_size);#endif s->_raw_size = s->_cooked_size = globals->arm_glue_size; s->contents = foo; } if (globals->thumb_glue_size != 0) { BFD_ASSERT (globals->bfd_of_glue_owner != NULL); s = bfd_get_section_by_name (globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME); BFD_ASSERT (s != NULL); foo = (bfd_byte *) bfd_alloc (globals->bfd_of_glue_owner, globals->thumb_glue_size);#if 0 memset (foo, test_char, globals->thumb_glue_size);#endif s->_raw_size = s->_cooked_size = globals->thumb_glue_size; s->contents = foo; } return true;}static voidrecord_arm_to_thumb_glue (info, h) struct bfd_link_info * info; struct coff_link_hash_entry * h;{ const char * name = h->root.root.string; register asection * s; char * tmp_name; struct coff_link_hash_entry * myh; struct coff_arm_link_hash_table * globals; globals = coff_arm_hash_table (info); BFD_ASSERT (globals != NULL); BFD_ASSERT (globals->bfd_of_glue_owner != NULL); s = bfd_get_section_by_name (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME); BFD_ASSERT (s != NULL); tmp_name = ((char *) bfd_malloc (strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -