📄 ld.c
字号:
break; case N_SETB: reftype = "is a BSS set element"; break; case N_SETA: reftype = "is an absolute set element"; break; case N_SETV: reftype = "defined in data section as vector"; break; case N_INDR: reftype = (char *) alloca (23 + strlen ((nlist_p + 1)->n_un.n_strx + entry->strings)); sprintf (reftype, "defined equivalent to %s", (nlist_p + 1)->n_un.n_strx + entry->strings); break;#ifdef sequent case N_SHUNDF: reftype = "shared undf"; break;/* These conflict with cases above. case N_SHDATA: reftype = "shared data"; break; case N_SHBSS: reftype = "shared BSS"; break;*/ default: reftype = "I don't know this type"; break;#endif } fprintf (stderr, "symbol %s %s in ", sp->name, reftype); print_file_name (entry, stderr); fprintf (stderr, "\n"); }}/* This return 0 if the given file entry's symbol table does *not* contain the nlist point entry, and it returns the files entry pointer (cast to unsigned long) if it does. */unsigned longcontains_symbol (entry, n_ptr) struct file_entry *entry; register struct nlist *n_ptr;{ if (n_ptr >= entry->symbols && n_ptr < (entry->symbols + (entry->header.a_syms / sizeof (struct nlist)))) return (unsigned long) entry; return 0;}/* Searching libraries */struct file_entry *decode_library_subfile ();void linear_library (), symdef_library ();/* Search the library ENTRY, already open on descriptor DESC. This means deciding which library members to load, making a chain of `struct file_entry' for those members, and entering their global symbols in the hash table. */voidsearch_library (desc, entry) int desc; struct file_entry *entry;{ int member_length; register char *name; register struct file_entry *subentry; if (!undefined_global_sym_count) return; /* Examine its first member, which starts SARMAG bytes in. */ subentry = decode_library_subfile (desc, entry, SARMAG, &member_length); if (!subentry) return; name = subentry->filename; free (subentry); /* Search via __.SYMDEF if that exists, else linearly. */ if (!strcmp (name, "__.SYMDEF")) symdef_library (desc, entry, member_length); else linear_library (desc, entry);}/* Construct and return a file_entry for a library member. The library's file_entry is library_entry, and the library is open on DESC. SUBFILE_OFFSET is the byte index in the library of this member's header. We store the length of the member into *LENGTH_LOC. */struct file_entry *decode_library_subfile (desc, library_entry, subfile_offset, length_loc) int desc; struct file_entry *library_entry; int subfile_offset; int *length_loc;{ int bytes_read; register int namelen; int member_length; register char *name; struct ar_hdr hdr1; register struct file_entry *subentry; lseek (desc, subfile_offset, 0); bytes_read = read (desc, &hdr1, sizeof hdr1); if (!bytes_read) return 0; /* end of archive */ if (sizeof hdr1 != bytes_read) fatal_with_file ("malformed library archive ", library_entry); if (sscanf (hdr1.ar_size, "%d", &member_length) != 1) fatal_with_file ("malformatted header of archive member in ", library_entry); subentry = (struct file_entry *) xmalloc (sizeof (struct file_entry)); bzero (subentry, sizeof (struct file_entry)); for (namelen = 0; namelen < sizeof hdr1.ar_name && hdr1.ar_name[namelen] != 0 && hdr1.ar_name[namelen] != ' ' && hdr1.ar_name[namelen] != '/'; namelen++); name = (char *) xmalloc (namelen+1); strncpy (name, hdr1.ar_name, namelen); name[namelen] = 0; subentry->filename = name; subentry->local_sym_name = name; subentry->symbols = 0; subentry->strings = 0; subentry->subfiles = 0; subentry->starting_offset = subfile_offset + sizeof hdr1; subentry->superfile = library_entry; subentry->library_flag = 0; subentry->header_read_flag = 0; subentry->just_syms_flag = 0; subentry->chain = 0; subentry->total_size = member_length; (*length_loc) = member_length; return subentry;}int subfile_wanted_p ();/* Search a library that has a __.SYMDEF member. DESC is a descriptor on which the library is open. The file pointer is assumed to point at the __.SYMDEF data. ENTRY is the library's file_entry. MEMBER_LENGTH is the length of the __.SYMDEF data. */voidsymdef_library (desc, entry, member_length) int desc; struct file_entry *entry; int member_length;{ int *symdef_data = (int *) xmalloc (member_length); register struct symdef *symdef_base; char *sym_name_base; int number_of_symdefs; int length_of_strings; int not_finished; int bytes_read; register int i; struct file_entry *prev = 0; int prev_offset = 0; bytes_read = read (desc, symdef_data, member_length); if (bytes_read != member_length) fatal_with_file ("malformatted __.SYMDEF in ", entry); number_of_symdefs = *symdef_data / sizeof (struct symdef); if (number_of_symdefs < 0 || number_of_symdefs * sizeof (struct symdef) + 2 * sizeof (int) > member_length) fatal_with_file ("malformatted __.SYMDEF in ", entry); symdef_base = (struct symdef *) (symdef_data + 1); length_of_strings = *(int *) (symdef_base + number_of_symdefs); if (length_of_strings < 0 || number_of_symdefs * sizeof (struct symdef) + length_of_strings + 2 * sizeof (int) > member_length) fatal_with_file ("malformatted __.SYMDEF in ", entry); sym_name_base = sizeof (int) + (char *) (symdef_base + number_of_symdefs); /* Check all the string indexes for validity. */ for (i = 0; i < number_of_symdefs; i++) { register int index = symdef_base[i].symbol_name_string_index; if (index < 0 || index >= length_of_strings || (index && *(sym_name_base + index - 1))) fatal_with_file ("malformatted __.SYMDEF in ", entry); } /* Search the symdef data for members to load. Do this until one whole pass finds nothing to load. */ not_finished = 1; while (not_finished) { not_finished = 0; /* Scan all the symbols mentioned in the symdef for ones that we need. Load the library members that contain such symbols. */ for (i = 0; (i < number_of_symdefs && (undefined_global_sym_count || common_defined_global_count)); i++) if (symdef_base[i].symbol_name_string_index >= 0) { register symbol *sp; sp = getsym_soft (sym_name_base + symdef_base[i].symbol_name_string_index); /* If we find a symbol that appears to be needed, think carefully about the archive member that the symbol is in. */ /* * Per Mike Karels' recommendation, we no longer load library * files if the only reference(s) that would be satisfied are * 'common' references. This prevents some problems with name * pollution (e.g. a global common 'utime' linked to a function). */ if (sp && sp->referenced && !sp->defined) { int junk; register int j; register int offset = symdef_base[i].library_member_offset; struct file_entry *subentry; /* Don't think carefully about any archive member more than once in a given pass. */ if (prev_offset == offset) continue; prev_offset = offset; /* Read the symbol table of the archive member. */ subentry = decode_library_subfile (desc, entry, offset, &junk); if (subentry == 0) fatal ("invalid offset for %s in symbol table of %s", sym_name_base + symdef_base[i].symbol_name_string_index, entry->filename); read_entry_symbols (desc, subentry); subentry->strings = (char *) malloc (subentry->string_size); read_entry_strings (desc, subentry); /* Now scan the symbol table and decide whether to load. */ if (!subfile_wanted_p (subentry)) { free (subentry->symbols); free (subentry); } else { /* This member is needed; load it. Since we are loading something on this pass, we must make another pass through the symdef data. */ not_finished = 1; enter_file_symbols (subentry); if (prev) prev->chain = subentry; else entry->subfiles = subentry; prev = subentry; /* Clear out this member's symbols from the symdef data so that following passes won't waste time on them. */ for (j = 0; j < number_of_symdefs; j++) { if (symdef_base[j].library_member_offset == offset) symdef_base[j].symbol_name_string_index = -1; } } /* We'll read the strings again if we need them again. */ free (subentry->strings); subentry->strings = 0; } } } free (symdef_data);}/* Search a library that has no __.SYMDEF. ENTRY is the library's file_entry. DESC is the descriptor it is open on. */voidlinear_library (desc, entry) int desc; struct file_entry *entry;{ register struct file_entry *prev = 0; register int this_subfile_offset = SARMAG; while (undefined_global_sym_count || common_defined_global_count) { int member_length; register struct file_entry *subentry; subentry = decode_library_subfile (desc, entry, this_subfile_offset, &member_length); if (!subentry) return; read_entry_symbols (desc, subentry); subentry->strings = (char *) alloca (subentry->string_size); read_entry_strings (desc, subentry); if (!subfile_wanted_p (subentry)) { free (subentry->symbols); free (subentry); } else { enter_file_symbols (subentry); if (prev) prev->chain = subentry; else entry->subfiles = subentry; prev = subentry; subentry->strings = 0; /* Since space will dissapear on return */ } this_subfile_offset += member_length + sizeof (struct ar_hdr); if (this_subfile_offset & 1) this_subfile_offset++; }}/* ENTRY is an entry for a library member. Its symbols have been read into core, but not entered. Return nonzero if we ought to load this member. */intsubfile_wanted_p (entry) struct file_entry *entry;{ register struct nlist *p; register struct nlist *end = entry->symbols + entry->header.a_syms / sizeof (struct nlist);#ifdef DOLLAR_KLUDGE register int dollar_cond = 0;#endif for (p = entry->symbols; p < end; p++) { register int type = p->n_type; register char *name = p->n_un.n_strx + entry->strings; /* If the symbol has an interesting definition, we could potentially want it. */ if (type & N_EXT && (type != (N_UNDF | N_EXT) || p->n_value#ifdef DOLLAR_KLUDGE || name[1] == '$'#endif ) && !SET_ELEMENT_P (type) && !set_element_prefixed_p (name)) { register symbol *sp = getsym_soft (name);#ifdef DOLLAR_KLUDGE if (name[1] == '$') { sp = getsym_soft (&name[2]); dollar_cond = 1; if (!sp) continue; if (sp->referenced) { if (write_map) { print_file_name (entry, stdout); fprintf (stdout, " needed due to $-conditional %s\n", name); } return 1; } continue; }#endif /* If this symbol has not been hashed, we can't be looking for it. */ if (!sp) continue; /* * We don't load a file if it merely satisfies a common reference * (see explanation above in symdef_library()). */ if (sp->referenced && !sp->defined) { /* This is a symbol we are looking for. It is either not yet defined or defined as a common. */#ifdef DOLLAR_KLUDGE if (dollar_cond) continue;#endif if (type == (N_UNDF | N_EXT)) { /* Symbol being defined as common. Remember this, but don't load subfile just for this. */ /* If it didn't used to be common, up the count of common symbols. */ if (!sp->max_common_size) common_defined_global_count++; if (sp->max_common_size < p->n_value) sp->max_common_size = p->n_value; if (!sp->defined) undefined_global_sym_count--; sp->defined = 1; continue; } if (write_map) { print_file_name (entry, stdout); fprintf (stdout, " needed due to %s\n", sp->name); } return 1; } } } return 0;}void consider_file_section_lengths (), relocate_file_addresses ();/* Having entered all the global symbols and found the sizes of sections of all files to be linked, make all appropriate deductions from this data. We propagate global
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -