📄 linker.c
字号:
h->type = bfd_link_hash_defined; h->u.def.section = section; h->u.def.value = value; /* If we have been asked to, we act like collect2 and identify all functions that might be global constructors and destructors and pass them up in a callback. We only do this for certain object file types, since many object file types can handle this automatically. */ if (collect && name[0] == '_') { const char *s; /* A constructor or destructor name starts like this: _+GLOBAL_[_.$][ID][_.$] where the first [_.$] and the second are the same character (we accept any character there, in case a new object file format comes along with even worse naming restrictions). */#define CONS_PREFIX "GLOBAL_"#define CONS_PREFIX_LEN (sizeof CONS_PREFIX - 1) s = name + 1; while (*s == '_') ++s; if (s[0] == 'G' && strncmp (s, CONS_PREFIX, CONS_PREFIX_LEN - 1) == 0) { char c; c = s[CONS_PREFIX_LEN + 1]; if ((c == 'I' || c == 'D') && s[CONS_PREFIX_LEN] == s[CONS_PREFIX_LEN + 2]) { /* If this is a definition of a symbol which was previously weakly defined, we are in trouble. We have already added a constructor entry for the weak defined symbol, and now we are trying to add one for the new symbol. Fortunately, this case should never arise in practice. */ if (oldtype == bfd_link_hash_defweak) abort (); if (! ((*info->callbacks->constructor) (info, c == 'I' ? true : false, h->root.string, abfd, section, value))) return false; } } } } break; case COM: /* We have found a common definition for a symbol. */ if (h->type == bfd_link_hash_new) bfd_link_add_undef (info->hash, h); h->type = bfd_link_hash_common; h->u.c.p = ((struct bfd_link_hash_common_entry *) bfd_hash_allocate (&info->hash->table, sizeof (struct bfd_link_hash_common_entry))); if (h->u.c.p == NULL) return false; h->u.c.size = value; /* Select a default alignment based on the size. This may be overridden by the caller. */ { unsigned int power; power = bfd_log2 (value); if (power > 4) power = 4; h->u.c.p->alignment_power = power; } /* The section of a common symbol is only used if the common symbol is actually allocated. It basically provides a hook for the linker script to decide which output section the common symbols should be put in. In most cases, the section of a common symbol will be bfd_com_section_ptr, the code here will choose a common symbol section named "COMMON", and the linker script will contain *(COMMON) in the appropriate place. A few targets use separate common sections for small symbols, and they require special handling. */ if (section == bfd_com_section_ptr) { h->u.c.p->section = bfd_make_section_old_way (abfd, "COMMON"); h->u.c.p->section->flags = SEC_ALLOC; } else if (section->owner != abfd) { h->u.c.p->section = bfd_make_section_old_way (abfd, section->name); h->u.c.p->section->flags = SEC_ALLOC; } else h->u.c.p->section = section; break; case REF: /* A reference to a defined symbol. */ if (h->next == NULL && info->hash->undefs_tail != h) h->next = h; break; case BIG: /* We have found a common definition for a symbol which already had a common definition. Use the maximum of the two sizes. */ BFD_ASSERT (h->type == bfd_link_hash_common); if (! ((*info->callbacks->multiple_common) (info, h->root.string, h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size, abfd, bfd_link_hash_common, value))) return false; if (value > h->u.c.size) { unsigned int power; h->u.c.size = value; /* Select a default alignment based on the size. This may be overridden by the caller. */ power = bfd_log2 (value); if (power > 4) power = 4; h->u.c.p->alignment_power = power; } break; case CREF: { bfd *obfd; /* We have found a common definition for a symbol which was already defined. FIXME: It would nice if we could report the BFD which defined an indirect symbol, but we don't have anywhere to store the information. */ if (h->type == bfd_link_hash_defined || h->type == bfd_link_hash_defweak) obfd = h->u.def.section->owner; else obfd = NULL; if (! ((*info->callbacks->multiple_common) (info, h->root.string, obfd, h->type, (bfd_vma) 0, abfd, bfd_link_hash_common, value))) return false; } break; case MIND: /* Multiple indirect symbols. This is OK if they both point to the same symbol. */ if (strcmp (h->u.i.link->root.string, string) == 0) break; /* Fall through. */ case MDEF: /* Handle a multiple definition. */ { asection *msec = NULL; bfd_vma mval = 0; switch (h->type) { case bfd_link_hash_defined: msec = h->u.def.section; mval = h->u.def.value; break; case bfd_link_hash_indirect: msec = bfd_ind_section_ptr; mval = 0; break; default: abort (); } /* Ignore a redefinition of an absolute symbol to the same value; it's harmless. */ if (h->type == bfd_link_hash_defined && bfd_is_abs_section (msec) && bfd_is_abs_section (section) && value == mval) break; if (! ((*info->callbacks->multiple_definition) (info, h->root.string, msec->owner, msec, mval, abfd, section, value))) return false; } break; case CIND: /* Create an indirect symbol from an existing common symbol. */ BFD_ASSERT (h->type == bfd_link_hash_common); if (! ((*info->callbacks->multiple_common) (info, h->root.string, h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size, abfd, bfd_link_hash_indirect, (bfd_vma) 0))) return false; /* Fall through. */ case IND: /* Create an indirect symbol. */ { struct bfd_link_hash_entry *inh; /* STRING is the name of the symbol we want to indirect to. */ inh = bfd_wrapped_link_hash_lookup (abfd, info, string, true, copy, false); if (inh == (struct bfd_link_hash_entry *) NULL) return false; if (inh->type == bfd_link_hash_indirect && inh->u.i.link == h) { (*_bfd_error_handler) (_("%s: indirect symbol `%s' to `%s' is a loop"), bfd_get_filename (abfd), name, string); bfd_set_error (bfd_error_invalid_operation); return false; } if (inh->type == bfd_link_hash_new) { inh->type = bfd_link_hash_undefined; inh->u.undef.abfd = abfd; bfd_link_add_undef (info->hash, inh); } /* If the indirect symbol has been referenced, we need to push the reference down to the symbol we are referencing. */ if (h->type != bfd_link_hash_new) { row = UNDEF_ROW; cycle = true; } h->type = bfd_link_hash_indirect; h->u.i.link = inh; } break; case SET: /* Add an entry to a set. */ if (! (*info->callbacks->add_to_set) (info, h, BFD_RELOC_CTOR, abfd, section, value)) return false; break; case WARNC: /* Issue a warning and cycle. */ if (h->u.i.warning != NULL) { if (! (*info->callbacks->warning) (info, h->u.i.warning, h->root.string, abfd, (asection *) NULL, (bfd_vma) 0)) return false; /* Only issue a warning once. */ h->u.i.warning = NULL; } /* Fall through. */ case CYCLE: /* Try again with the referenced symbol. */ h = h->u.i.link; cycle = true; break; case REFC: /* A reference to an indirect symbol. */ if (h->next == NULL && info->hash->undefs_tail != h) h->next = h; h = h->u.i.link; cycle = true; break; case WARN: /* Issue a warning. */ if (! (*info->callbacks->warning) (info, string, h->root.string, hash_entry_bfd (h), (asection *) NULL, (bfd_vma) 0)) return false; break; case CWARN: /* Warn if this symbol has been referenced already, otherwise add a warning. A symbol has been referenced if the next field is not NULL, or it is the tail of the undefined symbol list. The REF case above helps to ensure this. */ if (h->next != NULL || info->hash->undefs_tail == h) { if (! (*info->callbacks->warning) (info, string, h->root.string, hash_entry_bfd (h), (asection *) NULL, (bfd_vma) 0)) return false; break; } /* Fall through. */ case MWARN: /* Make a warning symbol. */ { struct bfd_link_hash_entry *sub; /* STRING is the warning to give. */ sub = ((struct bfd_link_hash_entry *) ((*info->hash->table.newfunc) ((struct bfd_hash_entry *) NULL, &info->hash->table, h->root.string))); if (sub == NULL) return false; *sub = *h; sub->type = bfd_link_hash_warning; sub->u.i.link = h; if (! copy) sub->u.i.warning = string; else { char *w; w = bfd_hash_allocate (&info->hash->table, strlen (string) + 1); if (w == NULL) return false; strcpy (w, string); sub->u.i.warning = w; } bfd_hash_replace (&info->hash->table, (struct bfd_hash_entry *) h, (struct bfd_hash_entry *) sub); if (hashp != NULL) *hashp = sub; } break; } } while (cycle); return true;}/* Generic final link routine. */boolean_bfd_generic_final_link (abfd, info) bfd *abfd; struct bfd_link_info *info;{ bfd *sub; asection *o; struct bfd_link_order *p; size_t outsymalloc; struct generic_write_global_symbol_info wginfo; bfd_get_outsymbols (abfd) = (asymbol **) NULL; bfd_get_symcount (abfd) = 0; outsymalloc = 0; /* Mark all sections which will be included in the output file. */ for (o = abfd->sections; o != NULL; o = o->next) for (p = o->link_order_head; p != NULL; p = p->next) if (p->type == bfd_indirect_link_order) p->u.indirect.section->linker_mark = true; /* Build the output symbol table. */ for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next) if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc)) return false; /* Accumulate the global symbols. */ wginfo.info = info; wginfo.output_bfd = abfd; wginfo.psymalloc = &outsymalloc; _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info), _bfd_generic_link_write_global_symbol, (PTR) &wginfo); /* Make sure we have a trailing NULL pointer on OUTSYMBOLS. We shouldn't really need one, since we have SYMCOUNT, but some old code still expects one. */ if (! generic_add_output_symbol (abfd, &outsymalloc, NULL)) return false; if (info->relocateable) { /* Allocate space for the output relocs for each section. */ for (o = abfd->se
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -