xcofflink.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,198 行 · 第 1/5 页
C
2,198 行
this = (max + min) / 2; raddr = relocs[this].r_vaddr; if (raddr > address) max = this; else if (raddr < address) min = this; else { min = this; break; } } if (relocs[min].r_vaddr < address) return min + 1; while (min > 0 && relocs[min - 1].r_vaddr == address) --min; return min;}/* Add all the symbols from an object file to the hash table. XCOFF is a weird format. A normal XCOFF .o files will have three COFF sections--.text, .data, and .bss--but each COFF section will contain many csects. These csects are described in the symbol table. From the linker's point of view, each csect must be considered a section in its own right. For example, a TOC entry is handled as a small XMC_TC csect. The linker must be able to merge different TOC entries together, which means that it must be able to extract the XMC_TC csects from the .data section of the input .o file. From the point of view of our linker, this is, of course, a hideous nightmare. We cope by actually creating sections for each csect, and discarding the original sections. We then have to handle the relocation entries carefully, since the only way to tell which csect they belong to is to examine the address. */static booleanxcoff_link_add_symbols (abfd, info) bfd *abfd; struct bfd_link_info *info;{ unsigned int n_tmask; unsigned int n_btshft; boolean default_copy; bfd_size_type symcount; struct xcoff_link_hash_entry **sym_hash; asection **csect_cache; bfd_size_type linesz; asection *o; asection *last_real; boolean keep_syms; asection *csect; unsigned int csect_index; asection *first_csect; bfd_size_type symesz; bfd_byte *esym; bfd_byte *esym_end; struct reloc_info_struct { struct internal_reloc *relocs; asection **csects; bfd_byte *linenos; } *reloc_info = NULL; keep_syms = obj_coff_keep_syms (abfd); if ((abfd->flags & DYNAMIC) != 0 && ! info->static_link) { if (! xcoff_link_add_dynamic_symbols (abfd, info)) return false; } if (info->hash->creator == abfd->xvec) { /* We need to build a .loader section, so we do it here. This won't work if we're producing an XCOFF output file with no XCOFF input files. FIXME. */ if (xcoff_hash_table (info)->loader_section == NULL) { asection *lsec; lsec = bfd_make_section_anyway (abfd, ".loader"); if (lsec == NULL) goto error_return; xcoff_hash_table (info)->loader_section = lsec; lsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY; } /* Likewise for the linkage section. */ if (xcoff_hash_table (info)->linkage_section == NULL) { asection *lsec; lsec = bfd_make_section_anyway (abfd, ".gl"); if (lsec == NULL) goto error_return; xcoff_hash_table (info)->linkage_section = lsec; lsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY); lsec->alignment_power = 2; } /* Likewise for the TOC section. */ if (xcoff_hash_table (info)->toc_section == NULL) { asection *tsec; tsec = bfd_make_section_anyway (abfd, ".tc"); if (tsec == NULL) goto error_return; xcoff_hash_table (info)->toc_section = tsec; tsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY); tsec->alignment_power = 2; } /* Likewise for the descriptor section. */ if (xcoff_hash_table (info)->descriptor_section == NULL) { asection *dsec; dsec = bfd_make_section_anyway (abfd, ".ds"); if (dsec == NULL) goto error_return; xcoff_hash_table (info)->descriptor_section = dsec; dsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY); dsec->alignment_power = 2; } /* Likewise for the .debug section. */ if (xcoff_hash_table (info)->debug_section == NULL && info->strip != strip_all) { asection *dsec; dsec = bfd_make_section_anyway (abfd, ".debug"); if (dsec == NULL) goto error_return; xcoff_hash_table (info)->debug_section = dsec; dsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY; } } if ((abfd->flags & DYNAMIC) != 0 && ! info->static_link) return true; n_tmask = coff_data (abfd)->local_n_tmask; n_btshft = coff_data (abfd)->local_n_btshft; /* Define macros so that ISFCN, et. al., macros work correctly. */#define N_TMASK n_tmask#define N_BTSHFT n_btshft if (info->keep_memory) default_copy = false; else default_copy = true; symcount = obj_raw_syment_count (abfd); /* We keep a list of the linker hash table entries that correspond to each external symbol. */ sym_hash = ((struct xcoff_link_hash_entry **) bfd_alloc (abfd, (symcount * sizeof (struct xcoff_link_hash_entry *)))); if (sym_hash == NULL && symcount != 0) goto error_return; coff_data (abfd)->sym_hashes = (struct coff_link_hash_entry **) sym_hash; memset (sym_hash, 0, (size_t) symcount * sizeof (struct xcoff_link_hash_entry *)); /* Because of the weird stuff we are doing with XCOFF csects, we can not easily determine which section a symbol is in, so we store the information in the tdata for the input file. */ csect_cache = ((asection **) bfd_alloc (abfd, symcount * sizeof (asection *))); if (csect_cache == NULL && symcount != 0) goto error_return; xcoff_data (abfd)->csects = csect_cache; memset (csect_cache, 0, (size_t) symcount * sizeof (asection *)); /* While splitting sections into csects, we need to assign the relocs correctly. The relocs and the csects must both be in order by VMA within a given section, so we handle this by scanning along the relocs as we process the csects. We index into reloc_info using the section target_index. */ reloc_info = ((struct reloc_info_struct *) bfd_malloc ((abfd->section_count + 1) * sizeof (struct reloc_info_struct))); if (reloc_info == NULL) goto error_return; memset ((PTR) reloc_info, 0, (abfd->section_count + 1) * sizeof (struct reloc_info_struct)); /* Read in the relocs and line numbers for each section. */ linesz = bfd_coff_linesz (abfd); last_real = NULL; for (o = abfd->sections; o != NULL; o = o->next) { last_real = o; if ((o->flags & SEC_RELOC) != 0) { reloc_info[o->target_index].relocs = xcoff_read_internal_relocs (abfd, o, true, (bfd_byte *) NULL, false, (struct internal_reloc *) NULL); reloc_info[o->target_index].csects = (asection **) bfd_malloc (o->reloc_count * sizeof (asection *)); if (reloc_info[o->target_index].csects == NULL) goto error_return; memset (reloc_info[o->target_index].csects, 0, o->reloc_count * sizeof (asection *)); } if ((info->strip == strip_none || info->strip == strip_some) && o->lineno_count > 0) { bfd_byte *linenos; linenos = (bfd_byte *) bfd_malloc (o->lineno_count * linesz); if (linenos == NULL) goto error_return; reloc_info[o->target_index].linenos = linenos; if (bfd_seek (abfd, o->line_filepos, SEEK_SET) != 0 || (bfd_read (linenos, linesz, o->lineno_count, abfd) != linesz * o->lineno_count)) goto error_return; } } /* Don't let the linker relocation routines discard the symbols. */ obj_coff_keep_syms (abfd) = true; csect = NULL; csect_index = 0; first_csect = NULL; symesz = bfd_coff_symesz (abfd); BFD_ASSERT (symesz == bfd_coff_auxesz (abfd)); esym = (bfd_byte *) obj_coff_external_syms (abfd); esym_end = esym + symcount * symesz; while (esym < esym_end) { struct internal_syment sym; union internal_auxent aux; const char *name; char buf[SYMNMLEN + 1]; int smtyp; flagword flags; asection *section; bfd_vma value; struct xcoff_link_hash_entry *set_toc; bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym); /* In this pass we are only interested in symbols with csect information. */ if (sym.n_sclass != C_EXT && sym.n_sclass != C_HIDEXT) { if (sym.n_sclass == C_FILE && csect != NULL) { xcoff_section_data (abfd, csect)->last_symndx = ((esym - (bfd_byte *) obj_coff_external_syms (abfd)) / symesz); csect = NULL; } if (csect != NULL) *csect_cache = csect; else if (first_csect == NULL || sym.n_sclass == C_FILE) *csect_cache = coff_section_from_bfd_index (abfd, sym.n_scnum); else *csect_cache = NULL; esym += (sym.n_numaux + 1) * symesz; sym_hash += sym.n_numaux + 1; csect_cache += sym.n_numaux + 1; continue; } name = _bfd_coff_internal_syment_name (abfd, &sym, buf); if (name == NULL) goto error_return; /* If this symbol has line number information attached to it, and we're not stripping it, count the number of entries and add them to the count for this csect. In the final link pass we are going to attach line number information by symbol, rather than by section, in order to more easily handle garbage collection. */ if ((info->strip == strip_none || info->strip == strip_some) && sym.n_numaux > 1 && csect != NULL && ISFCN (sym.n_type)) { union internal_auxent auxlin; bfd_coff_swap_aux_in (abfd, (PTR) (esym + symesz), sym.n_type, sym.n_sclass, 0, sym.n_numaux, (PTR) &auxlin); if (auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr != 0) { asection *enclosing; bfd_size_type linoff; enclosing = xcoff_section_data (abfd, csect)->enclosing; if (enclosing == NULL) { (*_bfd_error_handler) (_("%s: `%s' has line numbers but no enclosing section"), bfd_get_filename (abfd), name); bfd_set_error (bfd_error_bad_value); goto error_return; } linoff = (auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr - enclosing->line_filepos); if (linoff < enclosing->lineno_count * linesz) { struct internal_lineno lin; bfd_byte *linpstart; linpstart = (reloc_info[enclosing->target_index].linenos + linoff); bfd_coff_swap_lineno_in (abfd, (PTR) linpstart, (PTR) &lin); if (lin.l_lnno == 0 && ((bfd_size_type) lin.l_addr.l_symndx == ((esym - (bfd_byte *) obj_coff_external_syms (abfd)) / symesz))) { bfd_byte *linpend, *linp; linpend = (reloc_info[enclosing->target_index].linenos + enclosing->lineno_count * linesz); for (linp = linpstart + linesz; linp < linpend; linp += linesz) { bfd_coff_swap_lineno_in (abfd, (PTR) linp, (PTR) &lin); if (lin.l_lnno == 0) break; } csect->lineno_count += (linp - linpstart) / linesz; /* The setting of line_filepos will only be useful if all the line number entries for a csect are contiguous; this only matters for error reporting. */ if (csect->line_filepos == 0) csect->line_filepos = auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr; } } } } /* Pick up the csect auxiliary information. */ if (sym.n_numaux == 0) { (*_bfd_error_handler) (_("%s: class %d symbol `%s' has no aux entries"), bfd_get_filename (abfd), sym.n_sclass, name); bfd_set_error (bfd_error_bad_value); goto error_return; } bfd_coff_swap_aux_in (abfd, (PTR) (esym + symesz * sym.n_numaux), sym.n_type, sym.n_sclass, sym.n_numaux - 1, sym.n_numaux, (PTR) &aux); smtyp = SMTYP_SMTYP (aux.x_csect.x_smtyp); flags = BSF_GLOBAL; section = NULL; value = 0; set_toc = NULL; switch (smtyp) { default: (*_bfd_error_handler) (_("%s: symbol `%s' has unrecognized csect type %d"), bfd_get_filename (abfd), name, smtyp); bfd_set_error (bfd_error_bad_value); goto error_return; case XTY_ER: /* This is an external reference. */ if (sym.n_sclass == C_HIDEXT || sym.n_scnum != N_UNDEF || aux.x_csect.x_scnlen.l != 0) { (*_bfd_error_handler) (_("%s: bad XTY_ER symbol `%s': class %d scnum %d scnlen %d"), bfd_get_filename (abfd), name, sym.n_sclass, sym.n_scnum, aux.x_csect.x_scnlen.l); bfd_set_error (bfd_error_bad_value); goto error_return; } /* An XMC_XO external reference is actually a reference to an absolute location. */ if (aux.x_csect.x_smclas != XMC_XO) section = bfd_und_section_ptr; else { section = bfd_abs_section_ptr; value = sym.n_value; } break; case XTY_SD: /* This is a csect definition. */ if (csect != NULL) { xcoff_section_data (abfd, csect)->last_symndx = ((esym - (bfd_byte *) obj_coff_external_syms (abfd)) / symesz); } csect = NULL; csect_index = -1; /* When we see a TOC anchor, we record the TOC value. */ if (aux.x_csect.x_smclas == XMC_TC0) { if (sym.n_sclass != C_HIDEXT || aux.x_csect.x_scnlen.l != 0) { (*_bfd_error_handler)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?