ldlang.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,418 行 · 第 1/5 页
C
2,418 行
p->real = true; p->local_sym_name = name; p->just_syms_flag = true; p->search_dirs_flag = false; break; case lang_input_file_is_fake_enum: p->filename = name; p->is_archive = false; p->real = false; p->local_sym_name = name; p->just_syms_flag = false; p->search_dirs_flag = false; break; case lang_input_file_is_l_enum: p->is_archive = true; p->filename = name; p->real = true; p->local_sym_name = concat ("-l", name, (const char *) NULL); p->just_syms_flag = false; p->search_dirs_flag = true; break; case lang_input_file_is_marker_enum: p->filename = name; p->is_archive = false; p->real = false; p->local_sym_name = name; p->just_syms_flag = false; p->search_dirs_flag = true; break; case lang_input_file_is_search_file_enum: p->filename = name; p->is_archive = false; p->real = true; p->local_sym_name = name; p->just_syms_flag = false; p->search_dirs_flag = true; break; case lang_input_file_is_file_enum: p->filename = name; p->is_archive = false; p->real = true; p->local_sym_name = name; p->just_syms_flag = false; p->search_dirs_flag = false; break; default: FAIL (); } p->the_bfd = (bfd *) NULL; p->asymbols = (asymbol **) NULL; p->next_real_file = (lang_statement_union_type *) NULL; p->next = (lang_statement_union_type *) NULL; p->symbol_count = 0; p->dynamic = config.dynamic_link; p->whole_archive = whole_archive; p->loaded = false; lang_statement_append (&input_file_chain, (lang_statement_union_type *) p, &p->next_real_file); return p;}lang_input_statement_type *lang_add_input_file (name, file_type, target) const char *name; lang_input_file_enum_type file_type; const char *target;{ lang_has_input_file = true; return new_afile (name, file_type, target, true);}/* Build enough state so that the parser can build its tree. */voidlang_init (){ obstack_begin (&stat_obstack, 1000); stat_ptr = &statement_list; lang_list_init (stat_ptr); lang_list_init (&input_file_chain); lang_list_init (&lang_output_section_statement); lang_list_init (&file_chain); first_file = lang_add_input_file ((char *) NULL, lang_input_file_is_marker_enum, (char *) NULL); abs_output_section = lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME); abs_output_section->bfd_section = bfd_abs_section_ptr;}/*---------------------------------------------------------------------- A region is an area of memory declared with the MEMORY { name:org=exp, len=exp ... } syntax. We maintain a list of all the regions here. If no regions are specified in the script, then the default is used which is created when looked up to be the entire data space. */static lang_memory_region_type *lang_memory_region_list;static lang_memory_region_type **lang_memory_region_list_tail = &lang_memory_region_list;lang_memory_region_type *lang_memory_region_lookup (name) const char *const name;{ lang_memory_region_type *p; for (p = lang_memory_region_list; p != (lang_memory_region_type *) NULL; p = p->next) { if (strcmp (p->name, name) == 0) { return p; } }#if 0 /* This code used to always use the first region in the list as the default region. I changed it to instead use a region encompassing all of memory as the default region. This permits NOLOAD sections to work reasonably without requiring a region. People should specify what region they mean, if they really want a region. */ if (strcmp (name, "*default*") == 0) { if (lang_memory_region_list != (lang_memory_region_type *) NULL) { return lang_memory_region_list; } }#endif { lang_memory_region_type *new = (lang_memory_region_type *) stat_alloc (sizeof (lang_memory_region_type)); new->name = xstrdup (name); new->next = (lang_memory_region_type *) NULL; *lang_memory_region_list_tail = new; lang_memory_region_list_tail = &new->next; new->origin = 0; new->flags = 0; new->not_flags = 0; new->length = ~(bfd_size_type) 0; new->current = 0; new->had_full_message = false; return new; }}static lang_memory_region_type *lang_memory_default (section) asection *section;{ lang_memory_region_type *p; flagword sec_flags = section->flags; /* Override SEC_DATA to mean a writable section. */ if ((sec_flags & (SEC_ALLOC | SEC_READONLY | SEC_CODE)) == SEC_ALLOC) sec_flags |= SEC_DATA; for (p = lang_memory_region_list; p != (lang_memory_region_type *) NULL; p = p->next) { if ((p->flags & sec_flags) != 0 && (p->not_flags & sec_flags) == 0) { return p; } } return lang_memory_region_lookup ("*default*");}lang_output_section_statement_type *lang_output_section_find (name) const char *const name;{ lang_statement_union_type *u; lang_output_section_statement_type *lookup; for (u = lang_output_section_statement.head; u != (lang_statement_union_type *) NULL; u = lookup->next) { lookup = &u->output_section_statement; if (strcmp (name, lookup->name) == 0) { return lookup; } } return (lang_output_section_statement_type *) NULL;}lang_output_section_statement_type *lang_output_section_statement_lookup (name) const char *const name;{ lang_output_section_statement_type *lookup; lookup = lang_output_section_find (name); if (lookup == (lang_output_section_statement_type *) NULL) { lookup = (lang_output_section_statement_type *) new_stat (lang_output_section_statement, stat_ptr); lookup->region = (lang_memory_region_type *) NULL; lookup->lma_region = (lang_memory_region_type *) NULL; lookup->fill = 0; lookup->block_value = 1; lookup->name = name; lookup->next = (lang_statement_union_type *) NULL; lookup->bfd_section = (asection *) NULL; lookup->processed = false; lookup->sectype = normal_section; lookup->addr_tree = (etree_type *) NULL; lang_list_init (&lookup->children); lookup->memspec = (const char *) NULL; lookup->flags = 0; lookup->subsection_alignment = -1; lookup->section_alignment = -1; lookup->load_base = (union etree_union *) NULL; lookup->phdrs = NULL; lang_statement_append (&lang_output_section_statement, (lang_statement_union_type *) lookup, &lookup->next); } return lookup;}static voidlang_map_flags (flag) flagword flag;{ if (flag & SEC_ALLOC) minfo ("a"); if (flag & SEC_CODE) minfo ("x"); if (flag & SEC_READONLY) minfo ("r"); if (flag & SEC_DATA) minfo ("w"); if (flag & SEC_LOAD) minfo ("l");}voidlang_map (){ lang_memory_region_type *m; minfo (_("\nMemory Configuration\n\n")); fprintf (config.map_file, "%-16s %-18s %-18s %s\n", _("Name"), _("Origin"), _("Length"), _("Attributes")); for (m = lang_memory_region_list; m != (lang_memory_region_type *) NULL; m = m->next) { char buf[100]; int len; fprintf (config.map_file, "%-16s ", m->name); sprintf_vma (buf, m->origin); minfo ("0x%s ", buf); len = strlen (buf); while (len < 16) { print_space (); ++len; } minfo ("0x%V", m->length); if (m->flags || m->not_flags) {#ifndef BFD64 minfo (" ");#endif if (m->flags) { print_space (); lang_map_flags (m->flags); } if (m->not_flags) { minfo (" !"); lang_map_flags (m->not_flags); } } print_nl (); } fprintf (config.map_file, _("\nLinker script and memory map\n\n")); print_statements ();}/* Initialize an output section. */static voidinit_os (s) lang_output_section_statement_type *s;{ section_userdata_type *new; if (s->bfd_section != NULL) return; if (strcmp (s->name, DISCARD_SECTION_NAME) == 0) einfo (_("%P%F: Illegal use of `%s' section"), DISCARD_SECTION_NAME); new = ((section_userdata_type *) stat_alloc (sizeof (section_userdata_type))); s->bfd_section = bfd_get_section_by_name (output_bfd, s->name); if (s->bfd_section == (asection *) NULL) s->bfd_section = bfd_make_section (output_bfd, s->name); if (s->bfd_section == (asection *) NULL) { einfo (_("%P%F: output format %s cannot represent section called %s\n"), output_bfd->xvec->name, s->name); } s->bfd_section->output_section = s->bfd_section; /* We initialize an output sections output offset to minus its own vma to allow us to output a section through itself. */ s->bfd_section->output_offset = 0; get_userdata (s->bfd_section) = (PTR) new; /* If there is a base address, make sure that any sections it might mention are initialized. */ if (s->addr_tree != NULL) exp_init_os (s->addr_tree);}/* Make sure that all output sections mentioned in an expression are initialized. */static voidexp_init_os (exp) etree_type *exp;{ switch (exp->type.node_class) { case etree_assign: exp_init_os (exp->assign.src); break; case etree_binary: exp_init_os (exp->binary.lhs); exp_init_os (exp->binary.rhs); break; case etree_trinary: exp_init_os (exp->trinary.cond); exp_init_os (exp->trinary.lhs); exp_init_os (exp->trinary.rhs); break; case etree_unary: exp_init_os (exp->unary.child); break; case etree_name: switch (exp->type.node_code) { case ADDR: case LOADADDR: case SIZEOF: { lang_output_section_statement_type *os; os = lang_output_section_find (exp->name.name); if (os != NULL && os->bfd_section == NULL) init_os (os); } } break; default: break; }}/* Sections marked with the SEC_LINK_ONCE flag should only be linked once into the output. This routine checks each section, and arrange to discard it if a section of the same name has already been linked. If the section has COMDAT information, then it uses that to decide whether the section should be included. This code assumes that all relevant sections have the SEC_LINK_ONCE flag set; that is, it does not depend solely upon the section name. section_already_linked is called via bfd_map_over_sections. *//* This is the shape of the elements inside the already_linked hash table. It maps a name onto a list of already_linked elements with the same name. It's possible to get more than one element in a list if the COMDAT sections have different names. */struct already_linked_hash_entry{ struct bfd_hash_entry root; struct already_linked *entry;};struct already_linked{ struct already_linked *next; asection *sec;};/* The hash table. */static struct bfd_hash_table already_linked_table;static voidsection_already_linked (abfd, sec, data) bfd *abfd; asection *sec; PTR data;{ lang_input_statement_type *entry = (lang_input_statement_type *) data; flagword flags; const char *name; struct already_linked *l; struct already_linked_hash_entry *already_linked_list; /* If we are only reading symbols from this object, then we want to discard all sections. */ if (entry->just_syms_flag) { sec->output_section = bfd_abs_section_ptr; sec->output_offset = sec->vma; return; } flags = bfd_get_section_flags (abfd, sec); if ((flags & SEC_LINK_ONCE) == 0) return; /* FIXME: When doing a relocatable link, we may have trouble copying relocations in other sections that refer to local symbols in the section being discarded. Those relocations will have to be converted somehow; as of this writing I'm not sure that any of the backends handle that correctly. It is tempting to instead not discard link once sections when doing a relocatable link (technically, they should be discarded whenever we are building constructors). However, that fails, because the linker winds up combining all the link once sections into a single large link once section, which defeats the purpose of having link once sections in the first place. Also, not merging link once sections in a relocatable link causes trouble for MIPS ELF, which relies in link once semantics to handle the .reginfo section correctly. */ name = bfd_get_section_name (abfd, sec); already_linked_list = ((struct already_linked_hash_entry *) bfd_hash_lookup (&already_linked_table, name, true, false));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?