elf32-hppa.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,142 行 · 第 1/5 页
C
2,142 行
subclass. */ if (ret == NULL) { ret = ((struct elf32_hppa_stub_hash_entry *) bfd_hash_allocate (table, sizeof (struct elf32_hppa_stub_hash_entry))); if (ret == NULL) return NULL; } /* Call the allocation method of the superclass. */ ret = ((struct elf32_hppa_stub_hash_entry *) bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); if (ret) { /* Initialize the local fields. */ ret->stub_sec = NULL;#if ! LONG_BRANCH_PIC_IN_SHLIB ret->reloc_sec = NULL;#endif ret->stub_offset = 0; ret->target_value = 0; ret->target_section = NULL; ret->stub_type = hppa_stub_long_branch; ret->h = NULL; ret->id_sec = NULL; } return (struct bfd_hash_entry *) ret;}/* Initialize an entry in the link hash table. */static struct bfd_hash_entry *hppa_link_hash_newfunc (entry, table, string) struct bfd_hash_entry *entry; struct bfd_hash_table *table; const char *string;{ struct elf32_hppa_link_hash_entry *ret; ret = (struct elf32_hppa_link_hash_entry *) entry; /* Allocate the structure if it has not already been allocated by a subclass. */ if (ret == NULL) { ret = ((struct elf32_hppa_link_hash_entry *) bfd_hash_allocate (table, sizeof (struct elf32_hppa_link_hash_entry))); if (ret == NULL) return NULL; } /* Call the allocation method of the superclass. */ ret = ((struct elf32_hppa_link_hash_entry *) _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); if (ret) { /* Initialize the local fields. */#if ! LONG_BRANCH_PIC_IN_SHLIB ret->stub_reloc_sec = NULL;#endif ret->stub_cache = NULL;#if ! LONG_BRANCH_PIC_IN_SHLIB || RELATIVE_DYNAMIC_RELOCS ret->reloc_entries = NULL;#endif ret->maybe_pic_call = 0; ret->pic_call = 0; ret->plabel = 0; ret->plt_abs = 0; } return (struct bfd_hash_entry *) ret;}/* Create the derived linker hash table. The PA ELF port uses the derived hash table to keep information specific to the PA ELF linker (without using static variables). */static struct bfd_link_hash_table *elf32_hppa_link_hash_table_create (abfd) bfd *abfd;{ struct elf32_hppa_link_hash_table *ret; ret = ((struct elf32_hppa_link_hash_table *) bfd_alloc (abfd, sizeof (*ret))); if (ret == NULL) return NULL; if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, hppa_link_hash_newfunc)) { bfd_release (abfd, ret); return NULL; } /* Init the stub hash table too. */ if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc)) return NULL; ret->stub_bfd = NULL; ret->add_stub_section = NULL; ret->layout_sections_again = NULL; ret->stub_group = NULL; ret->sgot = NULL; ret->srelgot = NULL; ret->splt = NULL; ret->srelplt = NULL; ret->sdynbss = NULL; ret->srelbss = NULL; ret->text_segment_base = (bfd_vma) -1; ret->data_segment_base = (bfd_vma) -1; ret->multi_subspace = 0; ret->has_12bit_branch = 0; ret->has_17bit_branch = 0; ret->need_plt_stub = 0; return &ret->root.root;}/* Build a name for an entry in the stub hash table. */static char *hppa_stub_name (input_section, sym_sec, hash, rel) const asection *input_section; const asection *sym_sec; const struct elf32_hppa_link_hash_entry *hash; const Elf_Internal_Rela *rel;{ char *stub_name; size_t len; if (hash) { len = 8 + 1 + strlen (hash->elf.root.root.string) + 1 + 8 + 1; stub_name = bfd_malloc (len); if (stub_name != NULL) { sprintf (stub_name, "%08x_%s+%x", input_section->id & 0xffffffff, hash->elf.root.root.string, (int) rel->r_addend & 0xffffffff); } } else { len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1; stub_name = bfd_malloc (len); if (stub_name != NULL) { sprintf (stub_name, "%08x_%x:%x+%x", input_section->id & 0xffffffff, sym_sec->id & 0xffffffff, (int) ELF32_R_SYM (rel->r_info) & 0xffffffff, (int) rel->r_addend & 0xffffffff); } } return stub_name;}/* Look up an entry in the stub hash. Stub entries are cached because creating the stub name takes a bit of time. */static struct elf32_hppa_stub_hash_entry *hppa_get_stub_entry (input_section, sym_sec, hash, rel, hplink) const asection *input_section; const asection *sym_sec; struct elf32_hppa_link_hash_entry *hash; const Elf_Internal_Rela *rel; struct elf32_hppa_link_hash_table *hplink;{ struct elf32_hppa_stub_hash_entry *stub_entry; const asection *id_sec; /* If this input section is part of a group of sections sharing one stub section, then use the id of the first section in the group. Stub names need to include a section id, as there may well be more than one stub used to reach say, printf, and we need to distinguish between them. */ id_sec = hplink->stub_group[input_section->id].link_sec; if (hash != NULL && hash->stub_cache != NULL && hash->stub_cache->h == hash && hash->stub_cache->id_sec == id_sec) { stub_entry = hash->stub_cache; } else { char *stub_name; stub_name = hppa_stub_name (id_sec, sym_sec, hash, rel); if (stub_name == NULL) return NULL; stub_entry = hppa_stub_hash_lookup (&hplink->stub_hash_table, stub_name, false, false); if (stub_entry == NULL) { if (hash == NULL || hash->elf.root.type != bfd_link_hash_undefweak) (*_bfd_error_handler) (_("%s(%s+0x%lx): cannot find stub entry %s"), bfd_get_filename (input_section->owner), input_section->name, (long) rel->r_offset, stub_name); } else { if (hash != NULL) hash->stub_cache = stub_entry; } free (stub_name); } return stub_entry;}/* Add a new stub entry to the stub hash. Not all fields of the new stub entry are initialised. */static struct elf32_hppa_stub_hash_entry *hppa_add_stub (stub_name, section, hplink) const char *stub_name; asection *section; struct elf32_hppa_link_hash_table *hplink;{ asection *link_sec; asection *stub_sec; struct elf32_hppa_stub_hash_entry *stub_entry; link_sec = hplink->stub_group[section->id].link_sec; stub_sec = hplink->stub_group[section->id].stub_sec; if (stub_sec == NULL) { stub_sec = hplink->stub_group[link_sec->id].stub_sec; if (stub_sec == NULL) { size_t len; char *s_name; len = strlen (link_sec->name) + sizeof (STUB_SUFFIX); s_name = bfd_alloc (hplink->stub_bfd, len); if (s_name == NULL) return NULL; strcpy (s_name, link_sec->name); strcpy (s_name + len - sizeof (STUB_SUFFIX), STUB_SUFFIX); stub_sec = (*hplink->add_stub_section) (s_name, link_sec); if (stub_sec == NULL) return NULL; hplink->stub_group[link_sec->id].stub_sec = stub_sec; } hplink->stub_group[section->id].stub_sec = stub_sec; } /* Enter this entry into the linker stub hash table. */ stub_entry = hppa_stub_hash_lookup (&hplink->stub_hash_table, stub_name, true, false); if (stub_entry == NULL) { (*_bfd_error_handler) (_("%s: cannot create stub entry %s"), bfd_get_filename (section->owner), stub_name); return NULL; } stub_entry->stub_sec = stub_sec;#if ! LONG_BRANCH_PIC_IN_SHLIB stub_entry->reloc_sec = hplink->stub_group[section->id].reloc_sec;#endif stub_entry->stub_offset = 0; stub_entry->id_sec = link_sec; return stub_entry;}/* Determine the type of stub needed, if any, for a call. */static enum elf32_hppa_stub_typehppa_type_of_stub (input_sec, rel, hash, destination) asection *input_sec; const Elf_Internal_Rela *rel; struct elf32_hppa_link_hash_entry *hash; bfd_vma destination;{ bfd_vma location; bfd_vma branch_offset; bfd_vma max_branch_offset; unsigned int r_type; if (hash != NULL && (((hash->elf.root.type == bfd_link_hash_defined || hash->elf.root.type == bfd_link_hash_defweak) && hash->elf.root.u.def.section->output_section == NULL) || (hash->elf.root.type == bfd_link_hash_defweak && hash->elf.dynindx != -1 && hash->elf.plt.offset != (bfd_vma) -1) || hash->elf.root.type == bfd_link_hash_undefweak || hash->elf.root.type == bfd_link_hash_undefined || (hash->maybe_pic_call && !(input_sec->flags & SEC_HAS_GOT_REF)))) { /* If output_section is NULL, then it's a symbol defined in a shared library. We will need an import stub. Decide between hppa_stub_import and hppa_stub_import_shared later. For shared links we need stubs for undefined or weak syms too; They will presumably be resolved by the dynamic linker. */ return hppa_stub_import; } /* Determine where the call point is. */ location = (input_sec->output_offset + input_sec->output_section->vma + rel->r_offset); branch_offset = destination - location - 8; r_type = ELF32_R_TYPE (rel->r_info); /* Determine if a long branch stub is needed. parisc branch offsets are relative to the second instruction past the branch, ie. +8 bytes on from the branch instruction location. The offset is signed and counts in units of 4 bytes. */ if (r_type == (unsigned int) R_PARISC_PCREL17F) { max_branch_offset = (1 << (17-1)) << 2; } else if (r_type == (unsigned int) R_PARISC_PCREL12F) { max_branch_offset = (1 << (12-1)) << 2; } else /* R_PARISC_PCREL22F. */ { max_branch_offset = (1 << (22-1)) << 2; } if (branch_offset + max_branch_offset >= 2*max_branch_offset) {#if LONG_BRANCH_VIA_PLT if (hash != NULL && hash->elf.dynindx != -1 && hash->elf.plt.offset != (bfd_vma) -1 && hash->elf.type != STT_PARISC_MILLI) { /* If we are doing a shared link and find we need a long branch stub, then go via the .plt if possible. */ return hppa_stub_import; } else#endif return hppa_stub_long_branch; } return hppa_stub_none;}/* Build one linker stub as defined by the stub hash table entry GEN_ENTRY. IN_ARG contains the link info pointer. */#define LDIL_R1 0x20200000 /* ldil LR'XXX,%r1 */#define BE_SR4_R1 0xe0202002 /* be,n RR'XXX(%sr4,%r1) */#define BL_R1 0xe8200000 /* b,l .+8,%r1 */#define ADDIL_R1 0x28200000 /* addil LR'XXX,%r1,%r1 */#define DEPI_R1 0xd4201c1e /* depi 0,31,2,%r1 */#define ADDIL_DP 0x2b600000 /* addil LR'XXX,%dp,%r1 */#define LDW_R1_R21 0x48350000 /* ldw RR'XXX(%sr0,%r1),%r21 */#define BV_R0_R21 0xeaa0c000 /* bv %r0(%r21) */#define LDW_R1_R19 0x48330000 /* ldw RR'XXX(%sr0,%r1),%r19 */#define ADDIL_R19 0x2a600000 /* addil LR'XXX,%r19,%r1 */#define LDW_R1_DP 0x483b0000 /* ldw RR'XXX(%sr0,%r1),%dp */#define LDSID_R21_R1 0x02a010a1 /* ldsid (%sr0,%r21),%r1 */#define MTSP_R1 0x00011820 /* mtsp %r1,%sr0 */#define BE_SR0_R21 0xe2a00000 /* be 0(%sr0,%r21) */#define STW_RP 0x6bc23fd1 /* stw %rp,-24(%sr0,%sp) */#define BL_RP 0xe8400002 /* b,l,n XXX,%rp */#define NOP 0x08000240 /* nop */#define LDW_RP 0x4bc23fd1 /* ldw -24(%sr0,%sp),%rp */#define LDSID_RP_R1 0x004010a1 /* ldsid (%sr0,%rp),%r1 */#define BE_SR0_RP 0xe0400002 /* be,n 0(%sr0,%rp) */#ifndef R19_STUBS#define R19_STUBS 1#endif#if R19_STUBS#define LDW_R1_DLT LDW_R1_R19#else#define LDW_R1_DLT LDW_R1_DP#endifstatic booleanhppa_build_one_stub (gen_entry, in_arg) struct bfd_hash_entry *gen_entry; PTR in_arg;{ struct elf32_hppa_stub_hash_entry *stub_entry; struct bfd_link_info *info; struct elf32_hppa_link_hash_table *hplink; asection *stub_sec; bfd *stub_bfd; bfd_byte *loc; bfd_vma sym_value; bfd_vma insn; bfd_vma off; int val; int size; /* Massage our args to the form they really have. */ stub_entry = (struct elf32_hppa_stub_hash_entry *) gen_entry; info = (struct bfd_link_info *) in_arg; hplink = hppa_link_hash_table (info); stub_sec = stub_entry->stub_sec; /* Make a note of the offset within the stubs for this entry. */ stub_entry->stub_offset = stub_sec->_raw_size; loc = stub_sec->contents + stub_entry->stub_offset; stub_bfd = stub_sec->owner; switch (stub_entry->stub_type) { case hppa_stub_long_branch: /* Create the long branch. A long branch is formed with "ldil"
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?