📄 elf64-mips.c
字号:
(const Elf64_Mips_External_Rela *) src, &mirela); dst[0].r_offset = mirela.r_offset; dst[0].r_info = ELF32_R_INFO (mirela.r_sym, mirela.r_type); dst[0].r_addend = mirela.r_addend; dst[1].r_offset = mirela.r_offset; dst[1].r_info = ELF32_R_INFO (mirela.r_ssym, mirela.r_type2); dst[1].r_addend = 0; dst[2].r_offset = mirela.r_offset; dst[2].r_info = ELF32_R_INFO (STN_UNDEF, mirela.r_type3); dst[2].r_addend = 0;}/* Swap out a MIPS 64-bit Rel reloc. */static voidmips_elf64_be_swap_reloc_out (abfd, src, dst) bfd *abfd; const Elf_Internal_Rel *src; bfd_byte *dst;{ Elf64_Mips_Internal_Rel mirel; mirel.r_offset = src->r_offset; mirel.r_type = ELF32_R_TYPE (src->r_info); mirel.r_sym = ELF32_R_SYM (src->r_info); mirel.r_type2 = R_MIPS_NONE; mirel.r_ssym = STN_UNDEF; mirel.r_type3 = R_MIPS_NONE; mips_elf64_swap_reloc_out (abfd, &mirel, (Elf64_Mips_External_Rel *) dst);}/* Swap out a MIPS 64-bit Rela reloc. */static voidmips_elf64_be_swap_reloca_out (abfd, src, dst) bfd *abfd; const Elf_Internal_Rela *src; bfd_byte *dst;{ Elf64_Mips_Internal_Rela mirela; mirela.r_offset = src->r_offset; mirela.r_type = ELF32_R_TYPE (src->r_info); mirela.r_addend = src->r_addend; mirela.r_sym = ELF32_R_SYM (src->r_info); mirela.r_type2 = R_MIPS_NONE; mirela.r_ssym = STN_UNDEF; mirela.r_type3 = R_MIPS_NONE; mips_elf64_swap_reloca_out (abfd, &mirela, (Elf64_Mips_External_Rela *) dst);}/* A mapping from BFD reloc types to MIPS ELF reloc types. */struct elf_reloc_map{ bfd_reloc_code_real_type bfd_reloc_val; enum elf_mips_reloc_type elf_reloc_val;};static CONST struct elf_reloc_map mips_reloc_map[] ={ { BFD_RELOC_NONE, R_MIPS_NONE, }, { BFD_RELOC_16, R_MIPS_16 }, { BFD_RELOC_32, R_MIPS_32 }, { BFD_RELOC_64, R_MIPS_64 }, { BFD_RELOC_CTOR, R_MIPS_64 }, { BFD_RELOC_32_PCREL, R_MIPS_REL32 }, { BFD_RELOC_MIPS_JMP, R_MIPS_26 }, { BFD_RELOC_HI16_S, R_MIPS_HI16 }, { BFD_RELOC_LO16, R_MIPS_LO16 }, { BFD_RELOC_MIPS_GPREL, R_MIPS_GPREL16 }, { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL }, { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 }, { BFD_RELOC_16_PCREL, R_MIPS_PC16 }, { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 }, { BFD_RELOC_MIPS_GPREL32, R_MIPS_GPREL32 }, { BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 }, { BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 }, { BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 }, { BFD_RELOC_MIPS_CALL_LO16, R_MIPS_CALL_LO16 }, { BFD_RELOC_MIPS_SUB, R_MIPS_SUB }, { BFD_RELOC_MIPS_GOT_PAGE, R_MIPS_GOT_PAGE }, { BFD_RELOC_MIPS_GOT_OFST, R_MIPS_GOT_OFST }, { BFD_RELOC_MIPS_GOT_DISP, R_MIPS_GOT_DISP }};/* Given a BFD reloc type, return a howto structure. */static reloc_howto_type *mips_elf64_reloc_type_lookup (abfd, code) bfd *abfd ATTRIBUTE_UNUSED; bfd_reloc_code_real_type code;{ unsigned int i; for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); i++) { if (mips_reloc_map[i].bfd_reloc_val == code) { int v; v = (int) mips_reloc_map[i].elf_reloc_val; return &mips_elf64_howto_table_rel[v]; } } return NULL;}/* Since each entry in an SHT_REL or SHT_RELA section can represent up to three relocs, we must tell the user to allocate more space. */static longmips_elf64_get_reloc_upper_bound (abfd, sec) bfd *abfd ATTRIBUTE_UNUSED; asection *sec;{ return (sec->reloc_count * 3 + 1) * sizeof (arelent *);}/* Read the relocations from one reloc section. */static booleanmips_elf64_slurp_one_reloc_table (abfd, asect, symbols, rel_hdr) bfd *abfd; asection *asect; asymbol **symbols; const Elf_Internal_Shdr *rel_hdr;{ PTR allocated = NULL; bfd_byte *native_relocs; arelent *relents; arelent *relent; unsigned int count; unsigned int i; int entsize; reloc_howto_type *howto_table; allocated = (PTR) bfd_malloc (rel_hdr->sh_size); if (allocated == NULL) goto error_return; if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0 || (bfd_read (allocated, 1, rel_hdr->sh_size, abfd) != rel_hdr->sh_size)) goto error_return; native_relocs = (bfd_byte *) allocated; relents = asect->relocation + asect->reloc_count; entsize = rel_hdr->sh_entsize; BFD_ASSERT (entsize == sizeof (Elf64_Mips_External_Rel) || entsize == sizeof (Elf64_Mips_External_Rela)); count = rel_hdr->sh_size / entsize; if (entsize == sizeof (Elf64_Mips_External_Rel)) howto_table = mips_elf64_howto_table_rel; else howto_table = mips_elf64_howto_table_rela; relent = relents; for (i = 0; i < count; i++, native_relocs += entsize) { Elf64_Mips_Internal_Rela rela; boolean used_sym, used_ssym; int ir; if (entsize == sizeof (Elf64_Mips_External_Rela)) mips_elf64_swap_reloca_in (abfd, (Elf64_Mips_External_Rela *) native_relocs, &rela); else { Elf64_Mips_Internal_Rel rel; mips_elf64_swap_reloc_in (abfd, (Elf64_Mips_External_Rel *) native_relocs, &rel); rela.r_offset = rel.r_offset; rela.r_sym = rel.r_sym; rela.r_ssym = rel.r_ssym; rela.r_type3 = rel.r_type3; rela.r_type2 = rel.r_type2; rela.r_type = rel.r_type; rela.r_addend = 0; } /* Each entry represents up to three actual relocations. */ used_sym = false; used_ssym = false; for (ir = 0; ir < 3; ir++) { enum elf_mips_reloc_type type; switch (ir) { default: abort (); case 0: type = (enum elf_mips_reloc_type) rela.r_type; break; case 1: type = (enum elf_mips_reloc_type) rela.r_type2; break; case 2: type = (enum elf_mips_reloc_type) rela.r_type3; break; } if (type == R_MIPS_NONE) { /* There are no more relocations in this entry. If this is the first entry, we need to generate a dummy relocation so that the generic linker knows that there has been a break in the sequence of relocations applying to a particular address. */ if (ir == 0) { relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) relent->address = rela.r_offset; else relent->address = rela.r_offset - asect->vma; relent->addend = 0; relent->howto = &howto_table[(int) R_MIPS_NONE]; ++relent; } break; } /* Some types require symbols, whereas some do not. */ switch (type) { case R_MIPS_NONE: case R_MIPS_LITERAL: case R_MIPS_INSERT_A: case R_MIPS_INSERT_B: case R_MIPS_DELETE: relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; break; default: if (! used_sym) { if (rela.r_sym == 0) relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; else { asymbol **ps, *s; ps = symbols + rela.r_sym - 1; s = *ps; if ((s->flags & BSF_SECTION_SYM) == 0) relent->sym_ptr_ptr = ps; else relent->sym_ptr_ptr = s->section->symbol_ptr_ptr; } used_sym = true; } else if (! used_ssym) { switch (rela.r_ssym) { case RSS_UNDEF: relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; break; case RSS_GP: case RSS_GP0: case RSS_LOC: /* FIXME: I think these need to be handled using special howto structures. */ BFD_ASSERT (0); break; default: BFD_ASSERT (0); break; } used_ssym = true; } else relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; break; } /* The address of an ELF reloc is section relative for an object file, and absolute for an executable file or shared library. The address of a BFD reloc is always section relative. */ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) relent->address = rela.r_offset; else relent->address = rela.r_offset - asect->vma; relent->addend = rela.r_addend; relent->howto = &howto_table[(int) type]; ++relent; } } asect->reloc_count += relent - relents; if (allocated != NULL) free (allocated); return true; error_return: if (allocated != NULL) free (allocated); return false;}/* Read the relocations. On Irix 6, there can be two reloc sections associated with a single data section. */static booleanmips_elf64_slurp_reloc_table (abfd, asect, symbols, dynamic) bfd *abfd; asection *asect; asymbol **symbols; boolean dynamic;{ struct bfd_elf_section_data * const d = elf_section_data (asect); if (dynamic) { bfd_set_error (bfd_error_invalid_operation); return false; } if (asect->relocation != NULL || (asect->flags & SEC_RELOC) == 0 || asect->reloc_count == 0) return true; /* Allocate space for 3 arelent structures for each Rel structure. */ asect->relocation = ((arelent *) bfd_alloc (abfd, asect->reloc_count * 3 * sizeof (arelent))); if (asect->relocation == NULL) return false; /* The slurp_one_reloc_table routine increments reloc_count. */ asect->reloc_count = 0; if (! mips_elf64_slurp_one_reloc_table (abfd, asect, symbols, &d->rel_hdr)) return false; if (d->rel_hdr2 != NULL) { if (! mips_elf64_slurp_one_reloc_table (abfd, asect, symbols, d->rel_hdr2)) return false; } return true;}/* Write out the relocations. */static voidmips_elf64_write_relocs (abfd, sec, data) bfd *abfd; asection *sec; PTR data;{ boolean *failedp = (boolean *) data; unsigned int count; Elf_Internal_Shdr *rela_hdr; Elf64_Mips_External_Rela *ext_rela; unsigned int idx; asymbol *last_sym = 0; int last_sym_idx = 0; /* If we have already failed, don't do anything. */ if (*failedp) return; if ((sec->flags & SEC_RELOC) == 0) return; /* The linker backend writes the relocs out itself, and sets the reloc_count field to zero to inhibit writing them here. Also, sometimes the SEC_RELOC flag gets set even when there aren't any relocs. */ if (sec->reloc_count == 0) return; /* We can combine up to three relocs that refer to the same address if the latter relocs have no associated symbol. */ count = 0; for (idx = 0; idx < sec->reloc_count; idx++) { bfd_vma addr; unsigned int i; ++count; addr = sec->orelocation[idx]->address; for (i = 0; i < 2; i++) { arelent *r; if (idx + 1 >= sec->reloc_count) break; r = sec->orelocation[idx + 1]; if (r->address != addr || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section) || (*r->sym_ptr_ptr)->value != 0) break; /* We can merge the reloc at IDX + 1 with the reloc at IDX. */ ++idx; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -