📄 elf32-i386.c
字号:
struct bfd_link_info *info = (struct bfd_link_info *) inf; /* If a symbol has been forced local or we have found a regular definition for the symbolic link case, then we won't be needing any relocs. */ if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 && ((h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0 || info->symbolic)) { for (s = h->pcrel_relocs_copied; s != NULL; s = s->next) s->section->_raw_size -= s->count * sizeof (Elf32_External_Rel); } return true;}/* Relocate an i386 ELF section. */static booleanelf_i386_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;{ bfd *dynobj; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; bfd_vma *local_got_offsets; asection *sgot; asection *splt; asection *sreloc; Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; dynobj = elf_hash_table (info)->dynobj; symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; sym_hashes = elf_sym_hashes (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd); sreloc = NULL; splt = NULL; sgot = NULL; if (dynobj != NULL) { splt = bfd_get_section_by_name (dynobj, ".plt"); sgot = bfd_get_section_by_name (dynobj, ".got"); } rel = relocs; relend = relocs + input_section->reloc_count; for (; rel < relend; rel++) { int r_type; reloc_howto_type *howto; unsigned long r_symndx; struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; asection *sec; bfd_vma relocation; bfd_reloc_status_type r; unsigned int indx; r_type = ELF32_R_TYPE (rel->r_info); if (r_type == (int) R_386_GNU_VTINHERIT || r_type == (int) R_386_GNU_VTENTRY) continue; if ((indx = (unsigned) r_type) >= R_386_standard && ((indx = (unsigned) r_type - R_386_ext_offset) - R_386_standard >= R_386_ext - R_386_standard)) { bfd_set_error (bfd_error_bad_value); return false; } howto = elf_howto_table + indx; r_symndx = ELF32_R_SYM (rel->r_info); if (info->relocateable) { /* This is a relocateable link. We don't have to change anything, unless the reloc is against a section symbol, in which case we have to adjust according to where the section symbol winds up in the output section. */ if (r_symndx < symtab_hdr->sh_info) { sym = local_syms + r_symndx; if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) { bfd_vma val; sec = local_sections[r_symndx]; val = bfd_get_32 (input_bfd, contents + rel->r_offset); val += sec->output_offset + sym->st_value; bfd_put_32 (input_bfd, val, contents + rel->r_offset); } } continue; } /* This is a final link. */ h = NULL; sym = NULL; sec = NULL; if (r_symndx < symtab_hdr->sh_info) { sym = local_syms + r_symndx; sec = local_sections[r_symndx]; relocation = (sec->output_section->vma + sec->output_offset + sym->st_value); } else { h = sym_hashes[r_symndx - symtab_hdr->sh_info]; while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; if (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) { sec = h->root.u.def.section; if (r_type == R_386_GOTPC || (r_type == R_386_PLT32 && splt != NULL && h->plt.offset != (bfd_vma) -1) || (r_type == R_386_GOT32 && elf_hash_table (info)->dynamic_sections_created && (! info->shared || (! info->symbolic && h->dynindx != -1) || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)) || (info->shared && ((! info->symbolic && h->dynindx != -1) || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) && (r_type == R_386_32 || r_type == R_386_PC32) && ((input_section->flags & SEC_ALLOC) != 0 /* DWARF will emit R_386_32 relocations in its sections against symbols defined externally in shared libraries. We can't do anything with them here. */ || ((input_section->flags & SEC_DEBUGGING) != 0 && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)))) { /* In these cases, we don't need the relocation value. We check specially because in some obscure cases sec->output_section will be NULL. */ relocation = 0; } else if (sec->output_section == NULL) { (*_bfd_error_handler) (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"), bfd_get_filename (input_bfd), h->root.root.string, bfd_get_section_name (input_bfd, input_section)); relocation = 0; } else relocation = (h->root.u.def.value + sec->output_section->vma + sec->output_offset); } else if (h->root.type == bfd_link_hash_undefweak) relocation = 0; else if (info->shared && !info->symbolic && !info->no_undefined && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) relocation = 0; else { if (! ((*info->callbacks->undefined_symbol) (info, h->root.root.string, input_bfd, input_section, rel->r_offset, (!info->shared || info->no_undefined || ELF_ST_VISIBILITY (h->other))))) return false; relocation = 0; } } switch (r_type) { case R_386_GOT32: /* Relocation is to the entry for this symbol in the global offset table. */ BFD_ASSERT (sgot != NULL); 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, or the symbol was forced to be local because of a version file. 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, relocation, sgot->contents + off); h->got.offset |= 1; } } relocation = 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, relocation, 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_386_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; } relocation = sgot->output_offset + off; } break; case R_386_GOTOFF: /* Relocation is relative to the start of the global offset table. */ if (sgot == NULL) { sgot = bfd_get_section_by_name (dynobj, ".got"); BFD_ASSERT (sgot != NULL); } /* Note that sgot->output_offset is not involved in this calculation. We always want the start of .got. If we defined _GLOBAL_OFFSET_TABLE in a different way, as is permitted by the ABI, we might have to change this calculation. */ relocation -= sgot->output_section->vma; break; case R_386_GOTPC: /* Use global offset table as symbol value. */ if (sgot == NULL) { sgot = bfd_get_section_by_name (dynobj, ".got"); BFD_ASSERT (sgot != NULL); } relocation = sgot->output_section->vma; break; case R_386_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) break; if (h->plt.offset == (bfd_vma) -1 || splt == NULL) { /* We didn't make a PLT entry for this symbol. This happens when statically linking PIC code, or when using -Bsymbolic. */ break; } relocation = (splt->output_section->vma + splt->output_offset + h->plt.offset); break; case R_386_32: case R_386_PC32: if (info->shared && (input_section->flags & SEC_ALLOC) != 0 && (r_type != R_386_PC32 || (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; /* When generating a shared object, these relocations are copied into the output file to be resolved at run time. */ 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 false; if (strncmp (name, ".rel", 4) != 0 || strcmp (bfd_get_section_name (input_bfd, input_section), name + 4) != 0) { if (input_bfd->my_archive) (*_bfd_error_handler) (_("%s(%s): bad relocation section name `%s\'"), bfd_get_filename (input_bfd->my_archive), bfd_get_filename (input_bfd), name); else (*_bfd_error_handler) (_("%s: bad relocation section name `%s\'"), bfd_get_filename (input_bfd), name); return false; } 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_386_PC32) { BFD_ASSERT (h != NULL && h->dynindx != -1); relocate = false; outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_PC32); } else { /* h->dynindx may be -1 if this symbol was marked to become local. */ 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_386_RELATIVE); } else { BFD_ASSERT (h->dynindx != -1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -