elf64-hppa.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,237 行 · 第 1/5 页
C
2,237 行
len = *plen; buf = *pbuf; if (len < tlen) { if (buf) free (buf); *pbuf = buf = malloc (tlen); *plen = len = tlen; if (!buf) return NULL; } if (h) { memcpy (buf, h->root.root.string, nlen); buf[nlen++] = '+'; sprintf_vma (buf + nlen, rel->r_addend); } else { nlen = sprintf (buf, "%x:%lx", sec->id & 0xffffffff, (long) ELF64_R_SYM (rel->r_info)); if (rel->r_addend) { buf[nlen++] = '+'; sprintf_vma (buf + nlen, rel->r_addend); } } return buf;}/* SEC is a section containing relocs for an input BFD when linking; return a suitable section for holding relocs in the output BFD for a link. */static booleanget_reloc_section (abfd, hppa_info, sec) bfd *abfd; struct elf64_hppa_link_hash_table *hppa_info; asection *sec;{ const char *srel_name; asection *srel; bfd *dynobj; srel_name = (bfd_elf_string_from_elf_section (abfd, elf_elfheader(abfd)->e_shstrndx, elf_section_data(sec)->rel_hdr.sh_name)); if (srel_name == NULL) return false; BFD_ASSERT ((strncmp (srel_name, ".rela", 5) == 0 && strcmp (bfd_get_section_name (abfd, sec), srel_name+5) == 0) || (strncmp (srel_name, ".rel", 4) == 0 && strcmp (bfd_get_section_name (abfd, sec), srel_name+4) == 0)); dynobj = hppa_info->root.dynobj; if (!dynobj) hppa_info->root.dynobj = dynobj = abfd; srel = bfd_get_section_by_name (dynobj, srel_name); if (srel == NULL) { srel = bfd_make_section (dynobj, srel_name); if (srel == NULL || !bfd_set_section_flags (dynobj, srel, (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED | SEC_READONLY)) || !bfd_set_section_alignment (dynobj, srel, 3)) return false; } hppa_info->other_rel_sec = srel; return true;}/* Add a new entry to the list of dynamic relocations against DYN_H. We use this to keep a record of all the FPTR relocations against a particular symbol so that we can create FPTR relocations in the output file. */static booleancount_dyn_reloc (abfd, dyn_h, type, sec, sec_symndx, offset, addend) bfd *abfd; struct elf64_hppa_dyn_hash_entry *dyn_h; int type; asection *sec; int sec_symndx; bfd_vma offset; bfd_vma addend;{ struct elf64_hppa_dyn_reloc_entry *rent; rent = (struct elf64_hppa_dyn_reloc_entry *) bfd_alloc (abfd, sizeof (*rent)); if (!rent) return false; rent->next = dyn_h->reloc_entries; rent->type = type; rent->sec = sec; rent->sec_symndx = sec_symndx; rent->offset = offset; rent->addend = addend; dyn_h->reloc_entries = rent; return true;}/* Scan the RELOCS and record the type of dynamic entries that each referenced symbol needs. */static booleanelf64_hppa_check_relocs (abfd, info, sec, relocs) bfd *abfd; struct bfd_link_info *info; asection *sec; const Elf_Internal_Rela *relocs;{ struct elf64_hppa_link_hash_table *hppa_info; const Elf_Internal_Rela *relend; Elf_Internal_Shdr *symtab_hdr; const Elf_Internal_Rela *rel; asection *dlt, *plt, *stubs; char *buf; size_t buf_len; int sec_symndx; if (info->relocateable) return true; /* If this is the first dynamic object found in the link, create the special sections required for dynamic linking. */ if (! elf_hash_table (info)->dynamic_sections_created) { if (! bfd_elf64_link_create_dynamic_sections (abfd, info)) return false; } hppa_info = elf64_hppa_hash_table (info); symtab_hdr = &elf_tdata (abfd)->symtab_hdr; /* If necessary, build a new table holding section symbols indices for this BFD. This is disgusting. */ if (info->shared && hppa_info->section_syms_bfd != abfd) { unsigned long i; int highest_shndx; Elf_Internal_Sym *local_syms, *isym; Elf64_External_Sym *ext_syms, *esym; /* We're done with the old cache of section index to section symbol index information. Free it. ?!? Note we leak the last section_syms array. Presumably we could free it in one of the later routines in this file. */ if (hppa_info->section_syms) free (hppa_info->section_syms); /* Allocate memory for the internal and external symbols. */ local_syms = (Elf_Internal_Sym *) bfd_malloc (symtab_hdr->sh_info * sizeof (Elf_Internal_Sym)); if (local_syms == NULL) return false; ext_syms = (Elf64_External_Sym *) bfd_malloc (symtab_hdr->sh_info * sizeof (Elf64_External_Sym)); if (ext_syms == NULL) { free (local_syms); return false; } /* Read in the local symbols. */ if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0 || bfd_read (ext_syms, 1, (symtab_hdr->sh_info * sizeof (Elf64_External_Sym)), abfd) != (symtab_hdr->sh_info * sizeof (Elf64_External_Sym))) { free (local_syms); free (ext_syms); return false; } /* Swap in the local symbols, also record the highest section index referenced by the local symbols. */ isym = local_syms; esym = ext_syms; highest_shndx = 0; for (i = 0; i < symtab_hdr->sh_info; i++, esym++, isym++) { bfd_elf64_swap_symbol_in (abfd, esym, isym); if (isym->st_shndx > highest_shndx) highest_shndx = isym->st_shndx; } /* Now we can free the external symbols. */ free (ext_syms); /* Allocate an array to hold the section index to section symbol index mapping. Bump by one since we start counting at zero. */ highest_shndx++; hppa_info->section_syms = (int *) bfd_malloc (highest_shndx * sizeof (int)); /* Now walk the local symbols again. If we find a section symbol, record the index of the symbol into the section_syms array. */ for (isym = local_syms, i = 0; i < symtab_hdr->sh_info; i++, isym++) { if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) hppa_info->section_syms[isym->st_shndx] = i; } /* We are finished with the local symbols. Get rid of them. */ free (local_syms); /* Record which BFD we built the section_syms mapping for. */ hppa_info->section_syms_bfd = abfd; } /* Record the symbol index for this input section. We may need it for relocations when building shared libraries. When not building shared libraries this value is never really used, but assign it to zero to prevent out of bounds memory accesses in other routines. */ if (info->shared) { sec_symndx = _bfd_elf_section_from_bfd_section (abfd, sec); /* If we did not find a section symbol for this section, then something went terribly wrong above. */ if (sec_symndx == -1) return false; sec_symndx = hppa_info->section_syms[sec_symndx]; } else sec_symndx = 0; dlt = plt = stubs = NULL; buf = NULL; buf_len = 0; relend = relocs + sec->reloc_count; for (rel = relocs; rel < relend; ++rel) { enum { NEED_DLT = 1, NEED_PLT = 2, NEED_STUB = 4, NEED_OPD = 8, NEED_DYNREL = 16, }; struct elf_link_hash_entry *h = NULL; unsigned long r_symndx = ELF64_R_SYM (rel->r_info); struct elf64_hppa_dyn_hash_entry *dyn_h; int need_entry; const char *addr_name; boolean maybe_dynamic; int dynrel_type = R_PARISC_NONE; static reloc_howto_type *howto; if (r_symndx >= symtab_hdr->sh_info) { /* We're dealing with a global symbol -- find its hash entry and mark it as being referenced. */ long indx = r_symndx - symtab_hdr->sh_info; h = elf_sym_hashes (abfd)[indx]; 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; h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; } /* We can only get preliminary data on whether a symbol is locally or externally defined, as not all of the input files have yet been processed. Do something with what we know, as this may help reduce memory usage and processing time later. */ maybe_dynamic = false; if (h && ((info->shared && ! info->symbolic) || ! (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) || h->root.type == bfd_link_hash_defweak)) maybe_dynamic = true; howto = elf_hppa_howto_table + ELF64_R_TYPE (rel->r_info); need_entry = 0; switch (howto->type) { /* These are simple indirect references to symbols through the DLT. We need to create a DLT entry for any symbols which appears in a DLTIND relocation. */ case R_PARISC_DLTIND21L: case R_PARISC_DLTIND14R: case R_PARISC_DLTIND14F: case R_PARISC_DLTIND14WR: case R_PARISC_DLTIND14DR: need_entry = NEED_DLT; break; /* ?!? These need a DLT entry. But I have no idea what to do with the "link time TP value. */ case R_PARISC_LTOFF_TP21L: case R_PARISC_LTOFF_TP14R: case R_PARISC_LTOFF_TP14F: case R_PARISC_LTOFF_TP64: case R_PARISC_LTOFF_TP14WR: case R_PARISC_LTOFF_TP14DR: case R_PARISC_LTOFF_TP16F: case R_PARISC_LTOFF_TP16WF: case R_PARISC_LTOFF_TP16DF: need_entry = NEED_DLT; break; /* These are function calls. Depending on their precise target we may need to make a stub for them. The stub uses the PLT, so we need to create PLT entries for these symbols too. */ case R_PARISC_PCREL12F: case R_PARISC_PCREL17F: case R_PARISC_PCREL22F: case R_PARISC_PCREL32: case R_PARISC_PCREL64: case R_PARISC_PCREL21L: case R_PARISC_PCREL17R: case R_PARISC_PCREL17C: case R_PARISC_PCREL14R: case R_PARISC_PCREL14F: case R_PARISC_PCREL22C: case R_PARISC_PCREL14WR: case R_PARISC_PCREL14DR: case R_PARISC_PCREL16F: case R_PARISC_PCREL16WF: case R_PARISC_PCREL16DF: need_entry = (NEED_PLT | NEED_STUB); break; case R_PARISC_PLTOFF21L: case R_PARISC_PLTOFF14R: case R_PARISC_PLTOFF14F: case R_PARISC_PLTOFF14WR: case R_PARISC_PLTOFF14DR: case R_PARISC_PLTOFF16F: case R_PARISC_PLTOFF16WF: case R_PARISC_PLTOFF16DF: need_entry = (NEED_PLT); break; case R_PARISC_DIR64: if (info->shared || maybe_dynamic) need_entry = (NEED_DYNREL); dynrel_type = R_PARISC_DIR64; break; /* This is an indirect reference through the DLT to get the address of a OPD descriptor. Thus we need to make a DLT entry that points to an OPD entry. */ case R_PARISC_LTOFF_FPTR21L: case R_PARISC_LTOFF_FPTR14R: case R_PARISC_LTOFF_FPTR14WR: case R_PARISC_LTOFF_FPTR14DR: case R_PARISC_LTOFF_FPTR32: case R_PARISC_LTOFF_FPTR64: case R_PARISC_LTOFF_FPTR16F: case R_PARISC_LTOFF_FPTR16WF: case R_PARISC_LTOFF_FPTR16DF: if (info->shared || maybe_dynamic) need_entry = (NEED_DLT | NEED_OPD); else need_entry = (NEED_DLT | NEED_OPD); dynrel_type = R_PARISC_FPTR64; break; /* This is a simple OPD entry. */ case R_PARISC_FPTR64: if (info->shared || maybe_dynamic) need_entry = (NEED_OPD | NEED_DYNREL); else need_entry = (NEED_OPD); dynrel_type = R_PARISC_FPTR64; break; /* Add more cases as needed. */ } if (!need_entry) continue; /* Collect a canonical name for this address. */ addr_name = get_dyn_name (sec, h, rel, &buf, &buf_len); /* Collect the canonical entry data for this address. */ dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table, addr_name, true, true); BFD_ASSERT (dyn_h); /* Stash away enough information to be able to find this symbol regardless of whether or not it is local or global. */ dyn_h->h = h; dyn_h->owner = abfd; dyn_h->sym_indx = r_symndx; /* ?!? We may need to do some error checking in here. */ /* Create what's needed. */ if (need_entry & NEED_DLT) { if (! hppa_info->dlt_sec && ! get_dlt (abfd, info, hppa_info)) goto err_out; dyn_h->want_dlt = 1; } if (need_entry & NEED_PLT) { if (! hppa_info->plt_sec && ! get_plt (abfd, info, hppa_info)) goto err_out; dyn_h->want_plt = 1; } if (need_entry & NEED_STUB) { if (! hppa_info->stub_sec && ! get_stub (abfd, info, hppa_info)) goto err_out; dyn_h->want_stub = 1; } if (need_entry & NEED_OPD) { if (! hppa_info->opd_sec && ! get_opd (abfd, info, hppa_info)) goto err_out; dyn_h->want_opd = 1;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?