📄 elf64-x86-64.c
字号:
} } else if (strncmp (name, ".rela", 5) == 0) { if (s->_raw_size == 0) { /* If we don't need this section, strip it from the output file. This is mostly to handle .rela.bss and .rela.plt. We must create both sections in create_dynamic_sections, because they must be created before the linker maps input sections to output sections. The linker does that before adjust_dynamic_symbol is called, and it is that function which decides whether anything needs to go into these sections. */ strip = true; } else { asection *target; /* Remember whether there are any reloc sections other than .rela.plt. */ if (strcmp (name, ".rela.plt") != 0) { const char *outname; relocs = true; /* If this relocation section applies to a read only section, then we probably need a DT_TEXTREL entry. The entries in the .rela.plt section really apply to the .got section, which we created ourselves and so know is not readonly. */ outname = bfd_get_section_name (output_bfd, s->output_section); target = bfd_get_section_by_name (output_bfd, outname + 5); if (target != NULL && (target->flags & SEC_READONLY) != 0 && (target->flags & SEC_ALLOC) != 0) reltext = true; } /* We use the reloc_count field as a counter if we need to copy relocs into the output file. */ s->reloc_count = 0; } } else if (strncmp (name, ".got", 4) != 0) { /* It's not one of our sections, so don't allocate space. */ continue; } if (strip) { _bfd_strip_section_from_output (info, s); continue; } /* Allocate memory for the section contents. We use bfd_zalloc here in case unused entries are not reclaimed before the section's contents are written out. This should not happen, but this way if it does, we get a R_X86_64_NONE reloc instead of garbage. */ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); if (s->contents == NULL && s->_raw_size != 0) return false; } if (elf_hash_table (info)->dynamic_sections_created) { /* Add some entries to the .dynamic section. We fill in the values later, in elf64_x86_64_finish_dynamic_sections, but we must add the entries now so that we get the correct size for the .dynamic section. The DT_DEBUG entry is filled in by the dynamic linker and used by the debugger. */ if (! info->shared) { if (! bfd_elf64_add_dynamic_entry (info, DT_DEBUG, 0)) return false; } if (plt) { if (! bfd_elf64_add_dynamic_entry (info, DT_PLTGOT, 0) || ! bfd_elf64_add_dynamic_entry (info, DT_PLTRELSZ, 0) || ! bfd_elf64_add_dynamic_entry (info, DT_PLTREL, DT_RELA) || ! bfd_elf64_add_dynamic_entry (info, DT_JMPREL, 0)) return false; } if (relocs) { if (! bfd_elf64_add_dynamic_entry (info, DT_RELA, 0) || ! bfd_elf64_add_dynamic_entry (info, DT_RELASZ, 0) || ! bfd_elf64_add_dynamic_entry (info, DT_RELAENT, sizeof (Elf64_External_Rela))) return false; } if (reltext) { if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0)) return false; info->flags |= DF_TEXTREL; } } return true;}/* This function is called via elf64_x86_64_link_hash_traverse if we are creating a shared object. In the -Bsymbolic case, it discards the space allocated to copy PC relative relocs against symbols which are defined in regular objects. For the normal non-symbolic case, we also discard space for relocs that have become local due to symbol visibility changes. We allocated space for them in the check_relocs routine, but we won't fill them in in the relocate_section routine. */static booleanelf64_x86_64_discard_copies (h, inf) struct elf64_x86_64_link_hash_entry *h; PTR inf;{ struct elf64_x86_64_pcrel_relocs_copied *s; 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 (Elf64_External_Rela); } return true;}/* Relocate an x86_64 ELF section. */static booleanelf64_x86_64_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 *rela; 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 = splt = sgot = NULL; if (dynobj != NULL) { splt = bfd_get_section_by_name (dynobj, ".plt"); sgot = bfd_get_section_by_name (dynobj, ".got"); } rela = relocs; relend = relocs + input_section->reloc_count; for (; rela < relend; rela++) { 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 = ELF64_R_TYPE (rela->r_info); if ((indx = (unsigned) r_type) >= R_X86_64_max) { bfd_set_error (bfd_error_bad_value); return false; } howto = x86_64_elf_howto_table + indx; r_symndx = ELF64_R_SYM (rela->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) { sec = local_sections[r_symndx]; rela->r_addend += sec->output_offset + sym->st_value; } } 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_X86_64_PLT32 && splt != NULL && h->plt.offset != (bfd_vma) -1) || ((r_type == R_X86_64_GOT32 || r_type == R_X86_64_GOTPCREL) && 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_X86_64_8 || r_type == R_X86_64_16 || r_type == R_X86_64_32 || r_type == R_X86_64_64 || r_type == R_X86_64_PC8 || r_type == R_X86_64_PC16 || r_type == R_X86_64_PC32) && ((input_section->flags & SEC_ALLOC) != 0 /* DWARF will emit R_X86_64_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, rela->r_offset, (!info->shared || info->no_undefined || ELF_ST_VISIBILITY (h->other))))) return false; relocation = 0; } } /* When generating a shared object, the relocations handled here are copied into the output file to be resolved at run time. */ switch (r_type) { case R_X86_64_GOT32: /* Relocation is to the entry for this symbol in the global offset table. */ case R_X86_64_GOTPCREL: /* Use global offset table as symbol value. */ BFD_ASSERT (sgot != NULL); if (h != NULL) { bfd_vma 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 8, we use the least significant bit to record whether we have initialized it already. When doing a dynamic link, we create a .rela.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_64 (output_bfd, relocation, sgot->contents + off); h->got.offset |= 1; } } if (r_type == R_X86_64_GOTPCREL) relocation = sgot->output_section->vma + sgot->output_offset + off; else 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 8. 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_64 (output_bfd, relocation, sgot->contents + off); if (info->shared) { asection *srelgot; Elf_Internal_Rela outrel; /* We need to generate a R_X86_64_RELATIVE reloc for the dynamic linker. */ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); BFD_ASSERT (srelgot != NULL); outrel.r_offset = (sgot->output_section->vma + sgot->output_offset + off); outrel.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE); outrel.r_addend = relocation; bfd_elf64_swap_reloca_out (output_bfd, &outrel, (((Elf64_External_Rela *) srelgot->contents) + srelgot->reloc_count)); ++srelgot->reloc_count; } local_got_offsets[r_symndx] |= 1; } if (r_type == R_X86_64_GOTPCREL) relocation = sgot->output_section->vma + sgot->output_offset + off; else relocation = sgot->output_offset + off; } break; case R_X86_64_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_X86_64_PC8: case R_X86_64_PC16: case R_X86_64_PC32: if (h == NULL) break; /* Fall through. */ case R_X86_64_8: case R_X86_64_16: case R_X86_64_32: case R_X86_64_64: /* FIXME: The ABI says the linker should make sure the value is the same when it's zeroextended to 64 bit. */ if (info->shared && (input_section->flags & SEC_ALLOC) != 0 && ((r_type != R_X86_64_PC8 && r_type != R_X86_64_PC16 && r_type != R_X86_64_PC32) || (! info->symbolic || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0))) { Elf_Internal_Rela 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; BFD_ASSERT (strncmp (name, ".rela", 5) == 0 && strcmp (bfd_get_section_name (input_bfd, input_section), name + 5) == 0); 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 = rela->r_offset; else { bfd_vma off;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -