coff-alpha.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,226 行 · 第 1/5 页
C
2,226 行
/* Alpha ECOFF has a .pdata section. The lnnoptr field of the .pdata section is the number of entries it contains. Each entry takes up 8 bytes. The number of entries is required since the section is aligned to a 16 byte boundary. When we link .pdata sections together, we do not want to include the alignment bytes. We handle this on input by faking the size of the .pdata section to remove the unwanted alignment bytes. On output we will set the lnnoptr field and force the alignment. */ sec = bfd_get_section_by_name (abfd, _PDATA); if (sec != (asection *) NULL) { bfd_size_type size; size = sec->line_filepos * 8; BFD_ASSERT (size == bfd_section_size (abfd, sec) || size + 8 == bfd_section_size (abfd, sec)); if (! bfd_set_section_size (abfd, sec, size)) return NULL; } } return ret;}/* See whether the magic number matches. */static booleanalpha_ecoff_bad_format_hook (abfd, filehdr) bfd *abfd ATTRIBUTE_UNUSED; PTR filehdr;{ struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; if (ALPHA_ECOFF_BADMAG (*internal_f)) return false; return true;}/* This is a hook called by coff_real_object_p to create any backend specific information. */static PTRalpha_ecoff_mkobject_hook (abfd, filehdr, aouthdr) bfd *abfd; PTR filehdr; PTR aouthdr;{ PTR ecoff; ecoff = _bfd_ecoff_mkobject_hook (abfd, filehdr, aouthdr); if (ecoff != NULL) { struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; /* Set additional BFD flags according to the object type from the machine specific file header flags. */ switch (internal_f->f_flags & F_ALPHA_OBJECT_TYPE_MASK) { case F_ALPHA_SHARABLE: abfd->flags |= DYNAMIC; break; case F_ALPHA_CALL_SHARED: /* Always executable if using shared libraries as the run time loader might resolve undefined references. */ abfd->flags |= (DYNAMIC | EXEC_P); break; } } return ecoff;}/* Reloc handling. *//* Swap a reloc in. */static voidalpha_ecoff_swap_reloc_in (abfd, ext_ptr, intern) bfd *abfd; PTR ext_ptr; struct internal_reloc *intern;{ const RELOC *ext = (RELOC *) ext_ptr; intern->r_vaddr = bfd_h_get_64 (abfd, (bfd_byte *) ext->r_vaddr); intern->r_symndx = bfd_h_get_32 (abfd, (bfd_byte *) ext->r_symndx); BFD_ASSERT (bfd_header_little_endian (abfd)); intern->r_type = ((ext->r_bits[0] & RELOC_BITS0_TYPE_LITTLE) >> RELOC_BITS0_TYPE_SH_LITTLE); intern->r_extern = (ext->r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0; intern->r_offset = ((ext->r_bits[1] & RELOC_BITS1_OFFSET_LITTLE) >> RELOC_BITS1_OFFSET_SH_LITTLE); /* Ignored the reserved bits. */ intern->r_size = ((ext->r_bits[3] & RELOC_BITS3_SIZE_LITTLE) >> RELOC_BITS3_SIZE_SH_LITTLE); if (intern->r_type == ALPHA_R_LITUSE || intern->r_type == ALPHA_R_GPDISP) { /* Handle the LITUSE and GPDISP relocs specially. Its symndx value is not actually a symbol index, but is instead a special code. We put the code in the r_size field, and clobber the symndx. */ if (intern->r_size != 0) abort (); intern->r_size = intern->r_symndx; intern->r_symndx = RELOC_SECTION_NONE; } else if (intern->r_type == ALPHA_R_IGNORE) { /* The IGNORE reloc generally follows a GPDISP reloc, and is against the .lita section. The section is irrelevant. */ if (! intern->r_extern && intern->r_symndx == RELOC_SECTION_ABS) abort (); if (! intern->r_extern && intern->r_symndx == RELOC_SECTION_LITA) intern->r_symndx = RELOC_SECTION_ABS; }}/* Swap a reloc out. */static voidalpha_ecoff_swap_reloc_out (abfd, intern, dst) bfd *abfd; const struct internal_reloc *intern; PTR dst;{ RELOC *ext = (RELOC *) dst; long symndx; unsigned char size; /* Undo the hackery done in swap_reloc_in. */ if (intern->r_type == ALPHA_R_LITUSE || intern->r_type == ALPHA_R_GPDISP) { symndx = intern->r_size; size = 0; } else if (intern->r_type == ALPHA_R_IGNORE && ! intern->r_extern && intern->r_symndx == RELOC_SECTION_ABS) { symndx = RELOC_SECTION_LITA; size = intern->r_size; } else { symndx = intern->r_symndx; size = intern->r_size; } BFD_ASSERT (intern->r_extern || (intern->r_symndx >= 0 && intern->r_symndx <= 14)); bfd_h_put_64 (abfd, intern->r_vaddr, (bfd_byte *) ext->r_vaddr); bfd_h_put_32 (abfd, symndx, (bfd_byte *) ext->r_symndx); BFD_ASSERT (bfd_header_little_endian (abfd)); ext->r_bits[0] = ((intern->r_type << RELOC_BITS0_TYPE_SH_LITTLE) & RELOC_BITS0_TYPE_LITTLE); ext->r_bits[1] = ((intern->r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0) | ((intern->r_offset << RELOC_BITS1_OFFSET_SH_LITTLE) & RELOC_BITS1_OFFSET_LITTLE)); ext->r_bits[2] = 0; ext->r_bits[3] = ((size << RELOC_BITS3_SIZE_SH_LITTLE) & RELOC_BITS3_SIZE_LITTLE);}/* Finish canonicalizing a reloc. Part of this is generic to all ECOFF targets, and that part is in ecoff.c. The rest is done in this backend routine. It must fill in the howto field. */static voidalpha_adjust_reloc_in (abfd, intern, rptr) bfd *abfd; const struct internal_reloc *intern; arelent *rptr;{ if (intern->r_type > ALPHA_R_GPVALUE) abort (); switch (intern->r_type) { case ALPHA_R_BRADDR: case ALPHA_R_SREL16: case ALPHA_R_SREL32: case ALPHA_R_SREL64: /* This relocs appear to be fully resolved when they are against internal symbols. Against external symbols, BRADDR at least appears to be resolved against the next instruction. */ if (! intern->r_extern) rptr->addend = 0; else rptr->addend = - (intern->r_vaddr + 4); break; case ALPHA_R_GPREL32: case ALPHA_R_LITERAL: /* Copy the gp value for this object file into the addend, to ensure that we are not confused by the linker. */ if (! intern->r_extern) rptr->addend += ecoff_data (abfd)->gp; break; case ALPHA_R_LITUSE: case ALPHA_R_GPDISP: /* The LITUSE and GPDISP relocs do not use a symbol, or an addend, but they do use a special code. Put this code in the addend field. */ rptr->addend = intern->r_size; break; case ALPHA_R_OP_STORE: /* The STORE reloc needs the size and offset fields. We store them in the addend. */ BFD_ASSERT (intern->r_offset <= 256 && intern->r_size <= 256); rptr->addend = (intern->r_offset << 8) + intern->r_size; break; case ALPHA_R_OP_PUSH: case ALPHA_R_OP_PSUB: case ALPHA_R_OP_PRSHIFT: /* The PUSH, PSUB and PRSHIFT relocs do not actually use an address. I believe that the address supplied is really an addend. */ rptr->addend = intern->r_vaddr; break; case ALPHA_R_GPVALUE: /* Set the addend field to the new GP value. */ rptr->addend = intern->r_symndx + ecoff_data (abfd)->gp; break; case ALPHA_R_IGNORE: /* If the type is ALPHA_R_IGNORE, make sure this is a reference to the absolute section so that the reloc is ignored. For some reason the address of this reloc type is not adjusted by the section vma. We record the gp value for this object file here, for convenience when doing the GPDISP relocation. */ rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; rptr->address = intern->r_vaddr; rptr->addend = ecoff_data (abfd)->gp; break; default: break; } rptr->howto = &alpha_howto_table[intern->r_type];}/* When writing out a reloc we need to pull some values back out of the addend field into the reloc. This is roughly the reverse of alpha_adjust_reloc_in, except that there are several changes we do not need to undo. */static voidalpha_adjust_reloc_out (abfd, rel, intern) bfd *abfd ATTRIBUTE_UNUSED; const arelent *rel; struct internal_reloc *intern;{ switch (intern->r_type) { case ALPHA_R_LITUSE: case ALPHA_R_GPDISP: intern->r_size = rel->addend; break; case ALPHA_R_OP_STORE: intern->r_size = rel->addend & 0xff; intern->r_offset = (rel->addend >> 8) & 0xff; break; case ALPHA_R_OP_PUSH: case ALPHA_R_OP_PSUB: case ALPHA_R_OP_PRSHIFT: intern->r_vaddr = rel->addend; break; case ALPHA_R_IGNORE: intern->r_vaddr = rel->address; break; default: break; }}/* The size of the stack for the relocation evaluator. */#define RELOC_STACKSIZE (10)/* Alpha ECOFF relocs have a built in expression evaluator as well as other interdependencies. Rather than use a bunch of special functions and global variables, we use a single routine to do all the relocation for a section. I haven't yet worked out how the assembler is going to handle this. */static bfd_byte *alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, data, relocateable, symbols) bfd *abfd; struct bfd_link_info *link_info; struct bfd_link_order *link_order; bfd_byte *data; boolean relocateable; asymbol **symbols;{ bfd *input_bfd = link_order->u.indirect.section->owner; asection *input_section = link_order->u.indirect.section; long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); arelent **reloc_vector = NULL; long reloc_count; bfd *output_bfd = relocateable ? abfd : (bfd *) NULL; bfd_vma gp; boolean gp_undefined; bfd_vma stack[RELOC_STACKSIZE]; int tos = 0; if (reloc_size < 0) goto error_return; reloc_vector = (arelent **) bfd_malloc (reloc_size); if (reloc_vector == NULL && reloc_size != 0) goto error_return; if (! bfd_get_section_contents (input_bfd, input_section, data, (file_ptr) 0, input_section->_raw_size)) goto error_return; /* The section size is not going to change. */ input_section->_cooked_size = input_section->_raw_size; input_section->reloc_done = true; reloc_count = bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector, symbols); if (reloc_count < 0) goto error_return; if (reloc_count == 0) goto successful_return; /* Get the GP value for the output BFD. */ gp_undefined = false; gp = _bfd_get_gp_value (abfd); if (gp == 0) { if (relocateable != false) { asection *sec; bfd_vma lo; /* Make up a value. */ lo = (bfd_vma) -1; for (sec = abfd->sections; sec != NULL; sec = sec->next) { if (sec->vma < lo && (strcmp (sec->name, ".sbss") == 0 || strcmp (sec->name, ".sdata") == 0 || strcmp (sec->name, ".lit4") == 0 || strcmp (sec->name, ".lit8") == 0 || strcmp (sec->name, ".lita") == 0)) lo = sec->vma; } gp = lo + 0x8000; _bfd_set_gp_value (abfd, gp); } else { struct bfd_link_hash_entry *h; h = bfd_link_hash_lookup (link_info->hash, "_gp", false, false, true); if (h == (struct bfd_link_hash_entry *) NULL || h->type != bfd_link_hash_defined) gp_undefined = true; else { gp = (h->u.def.value + h->u.def.section->output_section->vma + h->u.def.section->output_offset); _bfd_set_gp_value (abfd, gp); } } } for (; *reloc_vector != (arelent *) NULL; reloc_vector++) { arelent *rel; bfd_reloc_status_type r; char *err; rel = *reloc_vector; r = bfd_reloc_ok; switch (rel->howto->type) { case ALPHA_R_IGNORE: rel->address += input_section->output_offset; break; case ALPHA_R_REFLONG: case ALPHA_R_REFQUAD: case ALPHA_R_BRADDR: case ALPHA_R_HINT: case ALPHA_R_SREL16: case ALPHA_R_SREL32: case ALPHA_R_SREL64: if (relocateable && ((*rel->sym_ptr_ptr)->flags & BSF_SECTION_SYM) == 0) { rel->address += input_section->output_offset; break; } r = bfd_perform_relocation (input_bfd, rel, data, input_section, output_bfd, &err); break; case ALPHA_R_GPREL32: /* This relocation is used in a switch table. It is a 32 bit offset from the current GP value. We must adjust it by the different between the original GP value and the current GP value. The original GP value is stored in the addend. We adjust the addend and let bfd_perform_relocation finish the job. */ rel->addend -= gp; r = bfd_perform_relocation (input_bfd, rel, data, input_section, output_bfd, &err); if (r == bfd_reloc_ok && gp_undefined) { r = bfd_reloc_dangerous; err = (char *) _("GP relative relocation used when GP not defined"); } break; case ALPHA_R_LITERAL: /* This is a reference to a literal value, generally (always?) in the .lita section. This is a 16 bit GP relative relocation. Sometimes the subsequent reloc is a LITUSE reloc, which indicates how this reloc is used. This sometimes permits rewriting the two instructions referred to by the LITERAL and the LITUSE into different instructions which do not refer to .lita. This can save
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?