elf32-hppa.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,142 行 · 第 1/5 页
C
2,142 行
int need_entry; r_symndx = ELF32_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) h = NULL; else h = ((struct elf32_hppa_link_hash_entry *) sym_hashes[r_symndx - symtab_hdr->sh_info]); r_type = ELF32_R_TYPE (rel->r_info); switch (r_type) { case R_PARISC_DLTIND14F: case R_PARISC_DLTIND14R: case R_PARISC_DLTIND21L: /* This symbol requires a global offset table entry. */ need_entry = NEED_GOT; /* Mark this section as containing PIC code. */ sec->flags |= SEC_HAS_GOT_REF; break; case R_PARISC_PLABEL14R: /* "Official" procedure labels. */ case R_PARISC_PLABEL21L: case R_PARISC_PLABEL32: /* If the addend is non-zero, we break badly. */ if (rel->r_addend != 0) abort (); /* If we are creating a shared library, then we need to create a PLT entry for all PLABELs, because PLABELs with local symbols may be passed via a pointer to another object. Additionally, output a dynamic relocation pointing to the PLT entry. For executables, the original 32-bit ABI allowed two different styles of PLABELs (function pointers): For global functions, the PLABEL word points into the .plt two bytes past a (function address, gp) pair, and for local functions the PLABEL points directly at the function. The magic +2 for the first type allows us to differentiate between the two. As you can imagine, this is a real pain when it comes to generating code to call functions indirectly or to compare function pointers. We avoid the mess by always pointing a PLABEL into the .plt, even for local functions. */ need_entry = PLT_PLABEL | NEED_PLT | NEED_DYNREL; break; case R_PARISC_PCREL12F: hplink->has_12bit_branch = 1; /* Fall thru. */ case R_PARISC_PCREL17C: case R_PARISC_PCREL17F: hplink->has_17bit_branch = 1; /* Fall thru. */ case R_PARISC_PCREL22F: /* Function calls might need to go through the .plt, and might require long branch stubs. */ if (h == NULL) { /* We know local syms won't need a .plt entry, and if they need a long branch stub we can't guarantee that we can reach the stub. So just flag an error later if we're doing a shared link and find we need a long branch stub. */ continue; } else { /* Global symbols will need a .plt entry if they remain global, and in most cases won't need a long branch stub. Unfortunately, we have to cater for the case where a symbol is forced local by versioning, or due to symbolic linking, and we lose the .plt entry. */ need_entry = NEED_PLT | NEED_STUBREL; if (h->elf.type == STT_PARISC_MILLI) need_entry = NEED_STUBREL; } break; case R_PARISC_SEGBASE: /* Used to set segment base. */ case R_PARISC_SEGREL32: /* Relative reloc, used for unwind. */ case R_PARISC_PCREL14F: /* PC relative load/store. */ case R_PARISC_PCREL14R: case R_PARISC_PCREL17R: /* External branches. */ case R_PARISC_PCREL21L: /* As above, and for load/store too. */ /* We don't need to propagate the relocation if linking a shared object since these are section relative. */ continue; case R_PARISC_DPREL14F: /* Used for gp rel data load/store. */ case R_PARISC_DPREL14R: case R_PARISC_DPREL21L: if (info->shared) { (*_bfd_error_handler) (_("%s: relocation %s can not be used when making a shared object; recompile with -fPIC"), bfd_get_filename (abfd), elf_hppa_howto_table[r_type].name); bfd_set_error (bfd_error_bad_value); return false; } /* Fall through. */ case R_PARISC_DIR17F: /* Used for external branches. */ case R_PARISC_DIR17R: case R_PARISC_DIR14F: /* Used for load/store from absolute locn. */ case R_PARISC_DIR14R: case R_PARISC_DIR21L: /* As above, and for ext branches too. */#if 1 /* Help debug shared library creation. Any of the above relocs can be used in shared libs, but they may cause pages to become unshared. */ if (info->shared) { (*_bfd_error_handler) (_("%s: relocation %s should not be used when making a shared object; recompile with -fPIC"), bfd_get_filename (abfd), elf_hppa_howto_table[r_type].name); } /* Fall through. */#endif case R_PARISC_DIR32: /* .word relocs. */ /* We may want to output a dynamic relocation later. */ need_entry = NEED_DYNREL; break; /* This relocation describes the C++ object vtable hierarchy. Reconstruct it for later use during GC. */ case R_PARISC_GNU_VTINHERIT: if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, &h->elf, rel->r_offset)) return false; continue; /* This relocation describes which C++ vtable entries are actually used. Record for later use during GC. */ case R_PARISC_GNU_VTENTRY: if (!_bfd_elf32_gc_record_vtentry (abfd, sec, &h->elf, rel->r_addend)) return false; continue; default: continue; } /* Now carry out our orders. */ if (need_entry & NEED_GOT) { /* Allocate space for a GOT entry, as well as a dynamic relocation for this entry. */ if (dynobj == NULL) hplink->root.dynobj = dynobj = abfd; if (hplink->sgot == NULL) { if (! elf32_hppa_create_dynamic_sections (dynobj, info)) return false; } if (h != NULL) { if (h->elf.got.refcount == -1) { h->elf.got.refcount = 1; /* Make sure this symbol is output as a dynamic symbol. */ if (h->elf.dynindx == -1) { if (! bfd_elf32_link_record_dynamic_symbol (info, &h->elf)) return false; } } else h->elf.got.refcount += 1; } else { /* This is a global offset table entry for a local symbol. */ if (local_got_refcounts == NULL) { size_t size; /* Allocate space for local got offsets and local plt offsets. Done this way to save polluting elf_obj_tdata with another target specific pointer. */ size = symtab_hdr->sh_info * 2 * sizeof (bfd_signed_vma); local_got_refcounts = ((bfd_signed_vma *) bfd_alloc (abfd, size)); if (local_got_refcounts == NULL) return false; elf_local_got_refcounts (abfd) = local_got_refcounts; memset (local_got_refcounts, -1, size); } if (local_got_refcounts[r_symndx] == -1) local_got_refcounts[r_symndx] = 1; else local_got_refcounts[r_symndx] += 1; } } if (need_entry & NEED_PLT) { /* If we are creating a shared library, and this is a reloc against a weak symbol or a global symbol in a dynamic object, then we will be creating an import stub and a .plt entry for the symbol. Similarly, on a normal link to symbols defined in a dynamic object we'll need the import stub and a .plt entry. We don't know yet whether the symbol is defined or not, so make an entry anyway and clean up later in adjust_dynamic_symbol. */ if ((sec->flags & SEC_ALLOC) != 0) { if (h != NULL) { if (h->elf.plt.refcount == -1) { h->elf.plt.refcount = 1; h->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; } else h->elf.plt.refcount += 1; /* If this .plt entry is for a plabel, mark it so that adjust_dynamic_symbol will keep the entry even if it appears to be local. */ if (need_entry & PLT_PLABEL) h->plabel = 1; } else if (need_entry & PLT_PLABEL) { int indx; if (local_got_refcounts == NULL) { size_t size; /* Allocate space for local got offsets and local plt offsets. */ size = symtab_hdr->sh_info * 2 * sizeof (bfd_signed_vma); local_got_refcounts = ((bfd_signed_vma *) bfd_alloc (abfd, size)); if (local_got_refcounts == NULL) return false; elf_local_got_refcounts (abfd) = local_got_refcounts; memset (local_got_refcounts, -1, size); } indx = r_symndx + symtab_hdr->sh_info; if (local_got_refcounts[indx] == -1) local_got_refcounts[indx] = 1; else local_got_refcounts[indx] += 1; } } } if (need_entry & (NEED_DYNREL | NEED_STUBREL)) { /* Flag this symbol as having a non-got, non-plt reference so that we generate copy relocs if it turns out to be dynamic. */ if (h != NULL) h->elf.elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; /* If we are creating a shared library then we need to copy the reloc into the shared library. However, if we are linking with -Bsymbolic, we need only copy absolute relocs or relocs against symbols that are not defined in an object we are including in the link. PC- or DP- or DLT-relative relocs against any local sym or global sym with DEF_REGULAR set, can be discarded. At this point we have not seen all the input files, so it is possible that DEF_REGULAR is not set now but will be set later (it is never cleared). We account for that possibility below by storing information in the reloc_entries field of the hash table entry. A similar situation to the -Bsymbolic case occurs when creating shared libraries and symbol visibility changes render the symbol local. As it turns out, all the relocs we will be creating here are absolute, so we cannot remove them on -Bsymbolic links or visibility changes anyway. A STUB_REL reloc is absolute too, as in that case it is the reloc in the stub we will be creating, rather than copying the PCREL reloc in the branch. */ if ((sec->flags & SEC_ALLOC) != 0 && info->shared#if RELATIVE_DYNAMIC_RELOCS && (!info->symbolic || is_absolute_reloc (r_type) || (h != NULL && ((h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)))#endif ) { boolean doit; asection *srel; srel = sreloc; if ((need_entry & NEED_STUBREL)) srel = stubreloc; /* Create a reloc section in dynobj and make room for this reloc. */ if (srel == NULL) { char *name; if (dynobj == NULL) hplink->root.dynobj = dynobj = abfd; name = bfd_elf_string_from_elf_section (abfd, elf_elfheader (abfd)->e_shstrndx, elf_section_data (sec)->rel_hdr.sh_name); if (name == NULL) { (*_bfd_error_handler) (_("Could not find relocation section for %s"), sec->name); bfd_set_error (bfd_error_bad_value); return false; } if ((need_entry & NEED_STUBREL)) { size_t len = strlen (name) + sizeof (STUB_SUFFIX); char *newname = bfd_malloc (len); if (newname == NULL) return false; strcpy (newname, name); strcpy (newname + len - sizeof (STUB_SUFFIX), STUB_SUFFIX); name = newname; } srel = bfd_get_section_by_name (dynobj, name); if (srel == NULL) { flagword flags; srel = bfd_make_section (dynobj, name); flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_IN_MEMORY | SEC_LINKER_CREATED); if ((sec->flags & SEC_ALLOC) != 0) flags |= SEC_ALLOC | SEC_LOAD; if (srel == NULL || !bfd_set_section_flags (dynobj, srel, flags) || !bfd_set_section_alignment (dynobj, srel, 2)) return false; } else if ((need_entry & NEED_STUBREL)) free (name); if ((need_entry & NEED_STUBREL)) stubreloc = srel; else sreloc = srel; }#if ! LONG_BRANCH_PIC_IN_SHLIB /* If this is a function call, we only need one dynamic reloc for the stub as all calls to a particular function will go through the same stub. Actually, a long branch stub needs two relocations, but we count on some intelligence on the part of the dynamic linker. */ if ((need_entry & NEED_STUBREL)) { doit = h->stub_reloc_sec != stubreloc; h->stub_reloc_sec = stubreloc; } else#endif doit = 1; if (doit) { srel->_raw_size += sizeof (Elf32_External_Rela);#if ! LONG_BRANCH_PIC_IN_SHLIB || RELATIVE_DYNAMIC_RELOCS /* Keep track of relocations we have entered for this global symbol, so that we can discard them later if necessary. */ if (h != NULL && (0#if RELATIVE_DYNAMIC_RELOCS || ! is_absolute_reloc (rtype)#endif || (need_entry & NEED_STUBREL))) { struct elf32_hppa_dyn_reloc_entry *p; for (p = h->reloc_entries; p != NULL; p = p->next) if (p->section == srel) break; if (p == NULL) { p = ((struct elf32_hppa_dyn_reloc_entry *) bfd_alloc (dynobj, sizeof *p)); if (p == NULL) return false; p->next = h->reloc_entries; h->reloc_entries = p; p->section = srel; p->count = 0; } /* NEED_STUBREL and NEED_DYNREL are never both set. Leave the count at zero for the NEED_STUBREL case as we only ever have one stub reloc per section per symbol, and this simplifies code in hppa_discard_copies. */ if (! (need_entry & NEED_STUBREL)) ++p->count; }#endif }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?