📄 coff-mips.c
字号:
symndx_to_section[RELOC_SECTION_NONE] = NULL; symndx_to_section[RELOC_SECTION_TEXT] = bfd_get_section_by_name (input_bfd, ".text"); symndx_to_section[RELOC_SECTION_RDATA] = bfd_get_section_by_name (input_bfd, ".rdata"); symndx_to_section[RELOC_SECTION_DATA] = bfd_get_section_by_name (input_bfd, ".data"); symndx_to_section[RELOC_SECTION_SDATA] = bfd_get_section_by_name (input_bfd, ".sdata"); symndx_to_section[RELOC_SECTION_SBSS] = bfd_get_section_by_name (input_bfd, ".sbss"); symndx_to_section[RELOC_SECTION_BSS] = bfd_get_section_by_name (input_bfd, ".bss"); symndx_to_section[RELOC_SECTION_INIT] = bfd_get_section_by_name (input_bfd, ".init"); symndx_to_section[RELOC_SECTION_LIT8] = bfd_get_section_by_name (input_bfd, ".lit8"); symndx_to_section[RELOC_SECTION_LIT4] = bfd_get_section_by_name (input_bfd, ".lit4"); symndx_to_section[RELOC_SECTION_XDATA] = NULL; symndx_to_section[RELOC_SECTION_PDATA] = NULL; symndx_to_section[RELOC_SECTION_FINI] = bfd_get_section_by_name (input_bfd, ".fini"); symndx_to_section[RELOC_SECTION_LITA] = NULL; symndx_to_section[RELOC_SECTION_ABS] = NULL; ecoff_data (input_bfd)->symndx_to_section = symndx_to_section; } sym_hashes = ecoff_data (input_bfd)->sym_hashes; gp = _bfd_get_gp_value (output_bfd); if (gp == 0) gp_undefined = true; else gp_undefined = false; got_lo = false; adjust = 0; if (ecoff_section_data (input_bfd, input_section) == NULL) offsets = NULL; else offsets = ecoff_section_data (input_bfd, input_section)->offsets; ext_rel = (struct external_reloc *) external_relocs; ext_rel_end = ext_rel + input_section->reloc_count; for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++) { struct internal_reloc int_rel; boolean use_lo = false; bfd_vma addend; reloc_howto_type *howto; struct ecoff_link_hash_entry *h = NULL; asection *s = NULL; bfd_vma relocation; bfd_reloc_status_type r; if (! got_lo) mips_ecoff_swap_reloc_in (input_bfd, (PTR) ext_rel, &int_rel); else { int_rel = lo_int_rel; got_lo = false; } BFD_ASSERT (int_rel.r_type < sizeof mips_howto_table / sizeof mips_howto_table[0]); /* The REFHI and RELHI relocs requires special handling. they must be followed by a REFLO or RELLO reloc, respectively, and the addend is formed from both relocs. */ if (int_rel.r_type == MIPS_R_REFHI || int_rel.r_type == MIPS_R_RELHI) { struct external_reloc *lo_ext_rel; /* As a GNU extension, permit an arbitrary number of REFHI or RELHI relocs before the REFLO or RELLO reloc. This permits gcc to emit the HI and LO relocs itself. */ for (lo_ext_rel = ext_rel + 1; lo_ext_rel < ext_rel_end; lo_ext_rel++) { mips_ecoff_swap_reloc_in (input_bfd, (PTR) lo_ext_rel, &lo_int_rel); if (lo_int_rel.r_type != int_rel.r_type) break; } if (lo_ext_rel < ext_rel_end && (lo_int_rel.r_type == (int_rel.r_type == MIPS_R_REFHI ? MIPS_R_REFLO : MIPS_R_RELLO)) && int_rel.r_extern == lo_int_rel.r_extern && int_rel.r_symndx == lo_int_rel.r_symndx) { use_lo = true; if (lo_ext_rel == ext_rel + 1) got_lo = true; } } howto = &mips_howto_table[int_rel.r_type]; /* The SWITCH reloc must be handled specially. This reloc is marks the location of a difference between two portions of an object file. The symbol index does not reference a symbol, but is actually the offset from the reloc to the subtrahend of the difference. This reloc is correct in the object file, and needs no further adjustment, unless we are relaxing. If we are relaxing, we may have to add in an offset. Since no symbols are involved in this reloc, we handle it completely here. */ if (int_rel.r_type == MIPS_R_SWITCH) { if (offsets != NULL && offsets[i] != 0) { r = _bfd_relocate_contents (howto, input_bfd, (bfd_vma) offsets[i], (contents + adjust + int_rel.r_vaddr - input_section->vma)); BFD_ASSERT (r == bfd_reloc_ok); } continue; } if (int_rel.r_extern) { h = sym_hashes[int_rel.r_symndx]; /* If h is NULL, that means that there is a reloc against an external symbol which we thought was just a debugging symbol. This should not happen. */ if (h == (struct ecoff_link_hash_entry *) NULL) abort (); } else { if (int_rel.r_symndx < 0 || int_rel.r_symndx >= NUM_RELOC_SECTIONS) s = NULL; else s = symndx_to_section[int_rel.r_symndx]; if (s == (asection *) NULL) abort (); } /* The GPREL reloc uses an addend: the difference in the GP values. */ if (int_rel.r_type != MIPS_R_GPREL && int_rel.r_type != MIPS_R_LITERAL) addend = 0; else { if (gp_undefined) { if (! ((*info->callbacks->reloc_dangerous) (info, _("GP relative relocation when GP not defined"), input_bfd, input_section, int_rel.r_vaddr - input_section->vma))) return false; /* Only give the error once per link. */ gp = 4; _bfd_set_gp_value (output_bfd, gp); gp_undefined = false; } if (! int_rel.r_extern) { /* This is a relocation against a section. The current addend in the instruction is the difference between INPUT_SECTION->vma and the GP value of INPUT_BFD. We must change this to be the difference between the final definition (which will end up in RELOCATION) and the GP value of OUTPUT_BFD (which is in GP). */ addend = ecoff_data (input_bfd)->gp - gp; } else if (! info->relocateable || h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) { /* This is a relocation against a defined symbol. The current addend in the instruction is simply the desired offset into the symbol (normally zero). We are going to change this into a relocation against a defined symbol, so we want the instruction to hold the difference between the final definition of the symbol (which will end up in RELOCATION) and the GP value of OUTPUT_BFD (which is in GP). */ addend = - gp; } else { /* This is a relocation against an undefined or common symbol. The current addend in the instruction is simply the desired offset into the symbol (normally zero). We are generating relocateable output, and we aren't going to define this symbol, so we just leave the instruction alone. */ addend = 0; } } /* If we are relaxing, mips_relax_section may have set offsets[i] to some value. A value of 1 means we must expand a PC relative branch into a multi-instruction of sequence, and any other value is an addend. */ if (offsets != NULL && offsets[i] != 0) { BFD_ASSERT (! info->relocateable); BFD_ASSERT (int_rel.r_type == MIPS_R_PCREL16 || int_rel.r_type == MIPS_R_RELHI || int_rel.r_type == MIPS_R_RELLO); if (offsets[i] != 1) addend += offsets[i]; else { bfd_byte *here; BFD_ASSERT (int_rel.r_extern && int_rel.r_type == MIPS_R_PCREL16); /* Move the rest of the instructions up. */ here = (contents + adjust + int_rel.r_vaddr - input_section->vma); memmove (here + PCREL16_EXPANSION_ADJUSTMENT, here, (size_t) (input_section->_raw_size - (int_rel.r_vaddr - input_section->vma))); /* Generate the new instructions. */ if (! mips_relax_pcrel16 (info, input_bfd, input_section, h, here, (input_section->output_section->vma + input_section->output_offset + (int_rel.r_vaddr - input_section->vma) + adjust))) return false; /* We must adjust everything else up a notch. */ adjust += PCREL16_EXPANSION_ADJUSTMENT; /* mips_relax_pcrel16 handles all the details of this relocation. */ continue; } } /* If we are relaxing, and this is a reloc against the .text segment, we may need to adjust it if some branches have been expanded. The reloc types which are likely to occur in the .text section are handled efficiently by mips_relax_section, and thus do not need to be handled here. */ if (ecoff_data (input_bfd)->debug_info.adjust != NULL && ! int_rel.r_extern && int_rel.r_symndx == RELOC_SECTION_TEXT && (strcmp (bfd_get_section_name (input_bfd, input_section), ".text") != 0 || (int_rel.r_type != MIPS_R_PCREL16 && int_rel.r_type != MIPS_R_SWITCH && int_rel.r_type != MIPS_R_RELHI && int_rel.r_type != MIPS_R_RELLO))) { bfd_vma adr; struct ecoff_value_adjust *a; /* We need to get the addend so that we know whether we need to adjust the address. */ BFD_ASSERT (int_rel.r_type == MIPS_R_REFWORD); adr = bfd_get_32 (input_bfd, (contents + adjust + int_rel.r_vaddr - input_section->vma)); for (a = ecoff_data (input_bfd)->debug_info.adjust; a != (struct ecoff_value_adjust *) NULL; a = a->next) { if (adr >= a->start && adr < a->end) addend += a->adjust; } } if (info->relocateable) { /* We are generating relocateable output, and must convert the existing reloc. */ if (int_rel.r_extern) { if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) && ! bfd_is_abs_section (h->root.u.def.section)) { const char *name; /* This symbol is defined in the output. Convert the reloc from being against the symbol to being against the section. */ /* Clear the r_extern bit. */ int_rel.r_extern = 0; /* Compute a new r_symndx value. */ s = h->root.u.def.section; name = bfd_get_section_name (output_bfd, s->output_section); int_rel.r_symndx = -1; switch (name[1]) { case 'b': if (strcmp (name, ".bss") == 0) int_rel.r_symndx = RELOC_SECTION_BSS; break; case 'd': if (strcmp (name, ".data") == 0) int_rel.r_symndx = RELOC_SECTION_DATA; break; case 'f': if (strcmp (name, ".fini") == 0) int_rel.r_symndx = RELOC_SECTION_FINI; break; case 'i': if (strcmp (name, ".init") == 0) int_rel.r_symndx = RELOC_SECTION_INIT; break; case 'l': if (strcmp (name, ".lit8") == 0) int_rel.r_symndx = RELOC_SECTION_LIT8; else if (strcmp (name, ".lit4") == 0) int_rel.r_symndx = RELOC_SECTION_LIT4; break; case 'r': if (strcmp (name, ".rdata") == 0) int_rel.r_symndx = RELOC_SECTION_RDATA; break; case 's': if (strcmp (name, ".sdata") == 0) int_rel.r_symndx = RELOC_SECTION_SDATA; else if (strcmp (name, ".sbss") == 0) int_rel.r_symndx = RELOC_SECTION_SBSS; break; case 't': if (strcmp (name, ".text") == 0) int_rel.r_symndx = RELOC_SECTION_TEXT; break; } if (int_rel.r_symndx == -1) abort (); /* Add the section VMA and the symbol value. */ relocation = (h->root.u.def.value + s->output_section->vma + s->output_offset); /* For a PC relative relocation, the object file currently holds just the addend. We must adjust by the address to get the right value. */ if (howto->pc_relative) { relocation -= int_rel.r_vaddr - input_section->vma; /* If we are converting a RELHI or RELLO reloc from being against an external symbol to being against a section, we must put a special value into the r_offset field. This value is the old addend. The r_offset for both the RELHI and RELLO relocs are the same, and we set both when we see RELHI. */ if (int_rel.r_type == MIPS_R_RELHI) { long addhi, addlo; addhi = bfd_get_32 (input_bfd, (contents + adjust + int_rel.r_vaddr - input_section->vma)); addhi &= 0xffff; if (addhi & 0x8000) addhi -= 0x10000; addhi <<= 16; if (! use_lo) addlo = 0; else { addlo = bfd_get_32 (input_bfd, (contents + adjust + lo_int_rel.r_vaddr - input_section->vma)); addlo &= 0xffff; if (addlo & 0x8000) addlo -= 0x10000; lo_int_rel.r_offset = addhi + addlo; } int_rel.r_offset = addhi + addlo; } } h = NULL; } else { /* Change the symndx value to the right one for the output BFD. */ int_rel.r_symndx = h->indx; if (int_rel.r_symndx == -1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -