aboutsummaryrefslogtreecommitdiff
path: root/ld/ldlang.c
diff options
context:
space:
mode:
Diffstat (limited to 'ld/ldlang.c')
-rw-r--r--ld/ldlang.c2231
1 files changed, 2231 insertions, 0 deletions
diff --git a/ld/ldlang.c b/ld/ldlang.c
new file mode 100644
index 0000000..1fccbc2
--- /dev/null
+++ b/ld/ldlang.c
@@ -0,0 +1,2231 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+
+This file is part of GLD, the Gnu Linker.
+
+GLD is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GLD is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GLD; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $Id$
+ *
+ * $Log$
+ * Revision 1.1 1991/03/21 21:28:45 gumby
+ * Initial revision
+ *
+ * Revision 1.3 1991/03/16 22:19:21 rich
+ * pop
+ *
+ * Revision 1.2 1991/03/15 18:52:42 rich
+ * pop
+ *
+ * Revision 1.1 1991/03/13 00:48:23 chrisb
+ * Initial revision
+ *
+ * Revision 1.8 1991/03/10 09:31:28 rich
+ * Modified Files:
+ * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.7 1991/03/09 03:31:03 sac
+ * After a fatal info message, the output file is deleted.
+ *
+ * Revision 1.6 1991/03/09 03:25:06 sac
+ * Added support for LONG, SHORT and BYTE keywords in scripts
+ *
+ * Revision 1.5 1991/03/06 21:59:31 sac
+ * Completed G++ support
+ *
+ * Revision 1.4 1991/03/06 02:26:02 sac
+ * Added support for constructor sections.
+ * Remove parsing ambiguity.
+ * Lint
+ *
+ * Revision 1.3 1991/02/22 17:15:01 sac
+ * Added RCS keywords and copyrights
+ *
+*/
+
+
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#include "ld.h"
+#include "ldmain.h"
+#include "ldsym.h"
+#include "ldgram.tab.h"
+#include "ldmisc.h"
+#include "ldlang.h"
+#include "ldexp.h"
+#include "ld-emul.h"
+#include "ldlex.h"
+
+/* EXPORTS */
+
+
+
+extern unsigned int undefined_global_sym_count;
+
+static char *startup_file;
+static lang_input_statement_type *first_file;
+lang_statement_list_type statement_list;
+lang_statement_list_type *stat_ptr = &statement_list;
+lang_statement_list_type lang_output_section_statement;
+lang_statement_list_type input_file_chain;
+lang_statement_list_type file_chain;
+extern char *current_file;
+static boolean placed_commons = false;
+
+boolean lang_float_flag;
+
+static lang_output_section_statement_type *default_common_section;
+
+
+/* FORWARDS */
+PROTO(static void, print_statements,(void));
+PROTO(static void, print_statement,(lang_statement_union_type *,
+ lang_output_section_statement_type *));
+
+
+
+/* EXPORTS */
+boolean lang_has_input_file = false;
+
+
+extern bfd *output_bfd;
+size_t largest_section;
+
+
+extern enum bfd_architecture ldfile_output_architecture;
+extern unsigned long ldfile_output_machine;
+extern char *ldfile_output_machine_name;
+
+
+extern ldsym_type *symbol_head;
+
+bfd_vma print_dot;
+unsigned int commons_pending;
+
+
+
+
+extern args_type command_line;
+extern ld_config_type config;
+
+char *entry_symbol;
+
+
+
+lang_output_section_statement_type *create_object_symbols;
+
+extern boolean had_script;
+static boolean map_option_f;
+
+
+boolean had_output_filename = false;
+extern boolean write_map;
+
+
+
+
+
+
+size_t longest_section_name = 8;
+
+
+lang_input_statement_type *script_file;
+
+section_userdata_type common_section_userdata;
+asection common_section;
+
+#ifdef __STDC__
+#define cat(a,b) a##b
+#else
+#define cat(a,b) a/**/b
+#endif
+
+#define new_stat(x,y) (cat(x,_type)*) new_statement(cat(x,_enum), sizeof(cat(x,_type)),y)
+
+#define outside_section_address(q) ( (q)->output_offset + (q)->output_section->vma)
+
+#define outside_symbol_address(q) ((q)->value + outside_section_address(q->section))
+
+boolean option_longmap = false;
+
+static void lang_list_init(list)
+lang_statement_list_type *list;
+{
+list->head = (lang_statement_union_type *)NULL;
+list->tail = &list->head;
+}
+
+static void
+print_section(name)
+char *name;
+{
+ printf("%*s", -longest_section_name, name);
+}
+static void
+print_space()
+{
+ printf(" ");
+}
+static void
+print_nl()
+{
+ printf("\n");
+}
+static void
+print_address(value)
+bfd_vma value;
+{
+ printf("%8lx", value);
+}
+static void
+print_size(value)
+size_t value;
+{
+ printf("%5x", (unsigned)value);
+}
+static void
+print_alignment(value)
+unsigned int value;
+{
+ printf("2**%2u",value);
+}
+static void
+print_fill(value)
+fill_type value;
+{
+ printf("%04x",(unsigned)value);
+}
+
+
+static
+lang_statement_union_type *new_statement(type, size, list)
+enum statement_enum type;
+size_t size;
+lang_statement_list_type *list;
+{
+ lang_statement_union_type *new = (lang_statement_union_type *)
+ ldmalloc(size);
+ new->header.type = type;
+ new->header.next = (lang_statement_union_type *)NULL;
+ lang_statement_append(list, new, &new->header.next);
+ return new;
+}
+
+static lang_input_statement_type *
+new_afile(name, file_type, target)
+char *name;
+lang_input_file_enum_type file_type;
+char *target;
+{
+ lang_input_statement_type *p = new_stat(lang_input_statement,
+ stat_ptr);
+ lang_has_input_file = true;
+ p->target = target;
+ switch (file_type) {
+ case lang_input_file_is_symbols_only_enum:
+ p->filename = name;
+ p->is_archive =false;
+ 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,"");
+ p->just_syms_flag = false;
+ p->search_dirs_flag = true;
+ break;
+
+ case lang_input_file_is_search_file_enum:
+ case lang_input_file_is_marker_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->asymbols = (asymbol **)NULL;
+ p->superfile = (lang_input_statement_type *)NULL;
+
+ p->next_real_file = (lang_statement_union_type*)NULL;
+ p->next = (lang_statement_union_type*)NULL;
+ p->symbol_count = 0;
+ p->common_output_section = (asection *)NULL;
+
+ 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)
+char *name;
+lang_input_file_enum_type file_type;
+char *target;
+{
+ /* Look it up or build a new one */
+
+ lang_input_statement_type *p;
+
+ for (p = (lang_input_statement_type *)input_file_chain.head;
+ p != (lang_input_statement_type *)NULL;
+ p = (lang_input_statement_type *)(p->next_real_file))
+ {
+ /* Sometimes we have incomplete entries in here */
+ if (p->filename != (char *)NULL) {
+ if(strcmp(name,p->filename) == 0) return p;
+ }
+ }
+
+ return new_afile(name, file_type, target);
+}
+
+
+
+void
+lang_init()
+{
+
+ 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);
+
+}
+
+static void
+lang_init2()
+{
+ script_file = lang_add_input_file("script file",
+ lang_input_file_is_fake_enum,
+ (char *)NULL);
+ script_file->the_bfd = bfd_create("script file", output_bfd);
+ script_file->symbol_count = 0;
+
+ common_section.userdata = &common_section_userdata;
+
+}
+
+
+
+/* this function mainains a dictionary of regions. If the *default*
+ region is asked for then a pointer to the first region is
+ returned. If there is no first pointer then one is created
+*/
+
+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)
+char *name;
+{
+
+ lang_memory_region_type *p = lang_memory_region_list;
+ for (p = lang_memory_region_list;
+ p != ( lang_memory_region_type *)NULL;
+ p = p->next) {
+ if (strcmp(p->name, name) == 0) {
+ return p;
+ }
+ }
+ if (strcmp(name,"*default*")==0) {
+ /* This is the default region, dig out first one on the list */
+ if (lang_memory_region_list != (lang_memory_region_type*)NULL){
+ return lang_memory_region_list;
+ }
+ }
+ {
+ lang_memory_region_type *new =
+ (lang_memory_region_type *)ldmalloc(sizeof(lang_memory_region_type));
+ new->name = 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->length = ~0;
+ new->current = 0;
+ return new;
+ }
+}
+
+
+
+lang_output_section_statement_type *
+lang_output_section_find(name)
+char *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)
+char *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->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->addr_tree = (etree_type *)NULL;
+ lang_list_init(&lookup->children);
+
+ lang_statement_append(&lang_output_section_statement,
+ (lang_statement_union_type *)lookup,
+ &lookup->next);
+ }
+ return lookup;
+}
+
+
+
+
+
+static void
+ print_flags(outfile, ignore_flags)
+FILE *outfile;
+lang_section_flags_type *ignore_flags;
+{
+ fprintf(outfile,"(");
+#if 0
+ if (flags->flag_read) fprintf(outfile,"R");
+ if (flags->flag_write) fprintf(outfile,"W");
+ if (flags->flag_executable) fprintf(outfile,"X");
+ if (flags->flag_loadable) fprintf(outfile,"L");
+#endif
+ fprintf(outfile,")");
+}
+
+void
+lang_map(outfile)
+ FILE *outfile;
+{
+ lang_memory_region_type *m;
+ fprintf(outfile,"**MEMORY CONFIGURATION**\n\n");
+
+ fprintf(outfile,"name\t\torigin\t\tlength\t\tattributes\n");
+ for (m = lang_memory_region_list;
+ m != (lang_memory_region_type *)NULL;
+ m = m->next)
+ {
+ fprintf(outfile,"%-16s", m->name);
+
+ fprintf(outfile,"%08lx\t%08lx\t", m->origin, m->length);
+ print_flags(outfile, &m->flags);
+ fprintf(outfile,"\n");
+ }
+ fprintf(outfile,"\n\n**LINK EDITOR MEMORY MAP**\n\n");
+ fprintf(outfile,"output\t\tinput\t\tvirtual\n");
+ fprintf(outfile,"section\t\tsection\t\taddress\tsize\n\n");
+
+ print_statements();
+
+}
+
+/*
+ *
+ */
+static void init_os(s)
+lang_output_section_statement_type *s;
+{
+ section_userdata_type *new =
+ (section_userdata_type *)
+ ldmalloc(sizeof(section_userdata_type));
+
+ s->bfd_section = bfd_make_section(output_bfd, s->name);
+ s->bfd_section->output_section = s->bfd_section;
+ s->bfd_section->flags = SEC_NO_FLAGS;
+ /* 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) = new;
+}
+
+static void
+wild_doit(ptr, section,output, file)
+lang_statement_list_type *ptr;
+asection *section;
+lang_output_section_statement_type *output;
+lang_input_statement_type *file;
+{
+ if(output->bfd_section == (asection *)NULL)
+ {
+ init_os(output);
+ }
+
+ if (section != (asection *)NULL
+ && section->output_section == (asection *)NULL) {
+ /* Add a section reference to the list */
+ lang_input_section_type *new = new_stat(lang_input_section, ptr);
+
+ new->section = section;
+ new->ifile = file;
+ section->output_section = output->bfd_section;
+ section->output_section->flags |= section->flags;
+ if (section->alignment_power > output->bfd_section->alignment_power) {
+ output->bfd_section->alignment_power = section->alignment_power;
+ }
+
+ }
+}
+
+static asection *
+our_bfd_get_section_by_name(abfd, section)
+bfd *abfd;
+char *section;
+{
+ return bfd_get_section_by_name(abfd, section);
+
+}
+static void
+wild_section(ptr, section, file , output)
+lang_wild_statement_type *ptr;
+char *section;
+lang_input_statement_type *file;
+lang_output_section_statement_type *output;
+{
+ asection *s;
+ if (section == (char *)NULL) {
+ /* Do the creation to all sections in the file */
+ for (s = file->the_bfd->sections; s != (asection *)NULL; s=s->next) {
+ wild_doit(&ptr->children, s, output, file);
+ }
+ }
+ else {
+ /* Do the creation to the named section only */
+ wild_doit(&ptr->children,
+ our_bfd_get_section_by_name(file->the_bfd, section),
+ output, file);
+ }
+
+
+
+}
+
+
+
+static
+lang_input_statement_type *lookup_name(name, target)
+char *name;
+char *target;
+{
+ lang_input_statement_type *search;
+ for(search = (lang_input_statement_type *)input_file_chain.head;
+ search != (lang_input_statement_type *)NULL;
+ search = (lang_input_statement_type *)search->next_real_file)
+ {
+ if (search->filename == (char *)NULL && name == (char *)NULL) {
+ return search;
+ }
+ if (search->filename != (char *)NULL && name != (char *)NULL) {
+ if (strcmp(search->filename, name) == 0) {
+ Q_read_file_symbols(search);
+ return search;
+ }
+ }
+ }
+
+ /* There isn't an afile entry for this file yet, this must be */
+ /* because the name has only appeared inside a load script and not */
+ /* on the command line */
+ search = new_afile(name, lang_input_file_is_file_enum, target);
+ Q_read_file_symbols(search);
+ return search;
+}
+
+static void
+
+wild(s, section, file, target, output)
+lang_wild_statement_type *s;
+char *section;
+char *file;
+char *target;
+lang_output_section_statement_type *output;
+{
+ lang_input_statement_type *f;
+ if (file == (char *)NULL) {
+ /* Perform the iteration over all files in the list */
+ for (f = (lang_input_statement_type *)file_chain.head;
+ f != (lang_input_statement_type *)NULL;
+ f = (lang_input_statement_type *)f->next) {
+ wild_section(s, section, f, output);
+ }
+ }
+ else {
+ /* Perform the iteration over a single file */
+ wild_section( s, section, lookup_name(file, target), output);
+ }
+}
+
+/*
+ read in all the files
+ */
+static bfd *
+open_output(name, target)
+char *name;
+char *target;
+{
+ extern char *output_filename;
+ bfd * output = bfd_openw(name, target);
+ output_filename = name;
+ if (output == (bfd *)NULL)
+ {
+ if (bfd_error == invalid_target) {
+ info("%P%F target %s not found\n", target);
+ }
+ info("%P%F problem opening output file %s, %E", name);
+ }
+
+ output->flags |= D_PAGED;
+ bfd_set_format(output, bfd_object);
+ return output;
+}
+extern char *default_target;
+static void
+lang_phase_0(sh,target)
+lang_statement_union_type *sh;
+char *target;
+{
+ lang_statement_union_type *s = (lang_statement_union_type *)sh;
+ for (; s != (lang_statement_union_type *)NULL ; s = s->next)
+ {
+ switch (s->header.type) {
+ case lang_output_section_statement_enum:
+ lang_phase_0(s->output_section_statement.children.head,
+ target);
+ break;
+ case lang_output_statement_enum:
+#if 1
+ output_bfd = open_output(s->output_statement.name,
+ target == (char *)NULL ?
+ default_target : target);
+ ldemul_set_output_arch();
+#endif
+ break;
+ case lang_target_statement_enum:
+ target = s->target_statement.target;
+ break;
+ case lang_wild_statement_enum:
+ /* Maybe we should load the file's symbols */
+ if (s->wild_statement.filename) {
+ (void) lookup_name(s->wild_statement.filename, target);
+ }
+ break;
+ /* Attatch this to the current output section */
+ case lang_common_statement_enum:
+ case lang_fill_statement_enum:
+ case lang_input_section_enum:
+ case lang_object_symbols_statement_enum:
+ case lang_address_statement_enum:
+ case lang_data_statement_enum:
+ break;
+ case lang_afile_asection_pair_statement_enum:
+
+ FAIL();
+ break;
+
+ case lang_input_statement_enum:
+ if (s->input_statement.real == true) {
+ s->input_statement.target = target;
+ lookup_name(s->input_statement.filename, target);
+ }
+ break;
+ case lang_assignment_statement_enum:
+#if 0
+ (void) exp_fold_tree(s->assignment_statement.exp,
+ output_section,
+ false);
+#endif
+ break;
+
+ case lang_padding_statement_enum:
+
+ break;
+ }
+ }
+
+}
+
+/* If there are [COMMONS] statements, put a wild one into the bss section */
+
+static void
+lang_reasonable_defaults()
+{
+ default_common_section =
+ lang_output_section_statement_lookup(".bss");
+ if (placed_commons == false) {
+ lang_wild_statement_type *new =
+ new_stat(lang_wild_statement,
+ &default_common_section->children);
+ new->section_name = "COMMON";
+ new->filename = (char *)NULL;
+ lang_list_init(&new->children);
+ }
+}
+
+static void lang()
+{
+ if (had_script == false) {
+ parse_line(ldemul_get_script());
+ }
+
+ lang_reasonable_defaults();
+ lang_phase_0(statement_list.head,default_target);
+}
+
+
+/* Open input files and attatch to output sections */
+static void
+lang_open_input(s, target, output_section_statement)
+lang_statement_union_type *s;
+char *target;
+lang_output_section_statement_type *output_section_statement;
+{
+ for (; s != (lang_statement_union_type *)NULL ; s = s->next)
+ {
+ switch (s->header.type) {
+ case lang_wild_statement_enum:
+ wild(&s->wild_statement, s->wild_statement.section_name,
+ s->wild_statement.filename, target,
+ output_section_statement);
+
+ break;
+
+ case lang_output_section_statement_enum:
+ lang_open_input(s->output_section_statement.children.head,
+ target,
+ &s->output_section_statement);
+ break;
+ case lang_output_statement_enum:
+ break;
+ case lang_target_statement_enum:
+ target = s->target_statement.target;
+ break;
+ case lang_common_statement_enum:
+ case lang_fill_statement_enum:
+ case lang_input_section_enum:
+ case lang_object_symbols_statement_enum:
+ case lang_data_statement_enum:
+ break;
+ case lang_afile_asection_pair_statement_enum:
+ FAIL();
+ break;
+
+ case lang_assignment_statement_enum:
+ case lang_padding_statement_enum:
+
+ break;
+ case lang_address_statement_enum:
+ /* Mark the specified section with the supplied address */
+ {
+ lang_output_section_statement_type *os =
+ lang_output_section_statement_lookup
+ (s->address_statement.section_name);
+ os->addr_tree = s->address_statement.address;
+ }
+ break;
+ case lang_input_statement_enum:
+ /* A standard input statement, has no wildcards */
+ /* Q_read_file_symbols(&s->input_statement);*/
+ break;
+ }
+ }
+}
+
+
+
+
+
+static void
+print_output_section_statement(output_section_statement)
+lang_output_section_statement_type *output_section_statement;
+{
+ asection *section = output_section_statement->bfd_section;
+ print_nl();
+ print_section(output_section_statement->name);
+
+ if (section) {
+ print_dot = section->vma;
+ print_space();
+ print_section("");
+ print_space();
+ print_address(section->vma);
+ print_space();
+ print_size(section->size);
+ print_space();
+ print_alignment(section->alignment_power);
+ print_space();
+#if 0
+ printf("%s flags", output_section_statement->region->name);
+ print_flags(stdout, &output_section_statement->flags);
+#endif
+
+ }
+ else {
+ printf("No attached output section");
+ }
+ print_nl();
+ print_statement(output_section_statement->children.head,
+ output_section_statement);
+
+}
+
+static void
+print_assignment(assignment, output_section)
+lang_assignment_statement_type *assignment;
+lang_output_section_statement_type *output_section;
+{
+ etree_value_type result;
+ print_section("");
+ print_space();
+ print_section("");
+ print_space();
+ print_address(print_dot);
+ print_space();
+ result = exp_fold_tree(assignment->exp->assign.src,
+ output_section,
+ lang_final_phase_enum,
+ print_dot,
+ &print_dot);
+
+ if (result.valid) {
+ print_address(result.value);
+ }
+ else
+ {
+ printf("*undefined*");
+ }
+ print_space();
+ exp_print_tree(stdout, assignment->exp);
+ printf("\n");
+}
+
+static void
+print_input_statement(statm)
+lang_input_statement_type *statm;
+{
+ printf("LOAD %s\n",statm->filename);
+}
+
+static void print_symbol(q)
+asymbol *q;
+{
+ print_section("");
+ printf(" ");
+ print_section("");
+ printf(" ");
+ print_address(outside_symbol_address(q));
+ printf(" %s", q->name ? q->name : " ");
+ print_nl();
+}
+static void
+print_input_section(in)
+lang_input_section_type *in;
+{
+ asection *i = in->section;
+
+ if(i->size != 0) {
+ print_section("");
+ printf(" ");
+ print_section(i->name);
+ printf(" ");
+ if (i->output_section) {
+ print_address(i->output_section->vma + i->output_offset);
+ printf(" ");
+ print_size(i->size);
+ printf(" ");
+ print_alignment(i->alignment_power);
+ printf(" ");
+ if (in->ifile) {
+ bfd *abfd = in->ifile->the_bfd;
+ printf(" %s ",abfd->xvec->name);
+ if(abfd->my_archive != (bfd *)NULL) {
+ printf("[%s]%s", abfd->my_archive->filename,
+ abfd->filename);
+ }
+ else {
+ printf("%s", abfd->filename);
+ }
+ print_nl();
+
+ /* Find all the symbols in this file defined in this section */
+ {
+ asymbol **p;
+ for (p = in->ifile->asymbols; *p; p++) {
+ asymbol *q = *p;
+
+ if (bfd_get_section(q) == i && q->flags & BSF_GLOBAL) {
+ print_symbol(q);
+ }
+ }
+ }
+ }
+ else {
+ print_nl();
+ }
+
+
+ print_dot = outside_section_address(i) + i->size;
+ }
+ else {
+ printf("No output section allocated\n");
+ }
+ }
+}
+static void
+print_common_statement()
+{
+ ldsym_type *lgs;
+ print_section("");
+ print_space();
+ print_section(common_section.output_section->name);
+ print_space();
+ print_address(common_section.output_offset +
+ common_section.output_section->vma);
+ print_space();
+ print_size(common_section.size);
+ print_space();
+ printf("(common)");
+ print_nl();
+ /* Print out all the global symbols */
+
+
+ for (lgs = symbol_head; lgs != (ldsym_type *)NULL; lgs =
+ lgs->next) {
+ if (lgs->sdefs_chain) {
+ asymbol *def = *(lgs->sdefs_chain);
+ if (def->section == &common_section) {
+ print_symbol(def);
+ }
+ }
+
+ }
+ print_dot = common_section.output_offset +
+ common_section.output_section->vma + common_section.size;
+
+
+}
+static void
+print_fill_statement(fill)
+lang_fill_statement_type *fill;
+{
+ printf("FILL mask ");
+ print_fill( fill->fill);
+}
+
+static void
+print_data_statement(data)
+lang_data_statement_type *data;
+{
+/* bfd_vma value; */
+ print_section("");
+ print_space();
+ print_section("");
+ print_space();
+ ASSERT(print_dot == data->output_vma);
+
+ print_address(data->output_vma);
+ print_space();
+ print_address(data->value);
+ print_space();
+ switch (data->type) {
+ case BYTE :
+ printf("BYTE ");
+ print_dot += BYTE_SIZE;
+ break;
+ case SHORT:
+ printf("SHORT ");
+ print_dot += SHORT_SIZE;
+ break;
+ case LONG:
+ printf("LONG ");
+ print_dot += LONG_SIZE;
+ break;
+ }
+
+ exp_print_tree(stdout, data->exp);
+
+ printf("\n");
+}
+
+
+static void
+print_padding_statement(s)
+lang_padding_statement_type *s;
+{
+ print_section("");
+ print_space();
+ print_section("*fill*");
+ print_space();
+ print_address(s->output_offset + s->output_section->vma);
+ print_space();
+ print_size(s->size);
+ print_space();
+ print_fill(s->fill);
+ print_nl();
+}
+
+static void print_wild_statement(w,os)
+lang_wild_statement_type *w;
+lang_output_section_statement_type *os;
+{
+ if (w->filename != (char *)NULL) {
+ printf("%s",w->filename);
+ }
+ else {
+ printf("*");
+ }
+ if (w->section_name != (char *)NULL) {
+ printf("(%s)",w->section_name);
+ }
+ else {
+ printf("(*)");
+ }
+ print_nl();
+ print_statement(w->children.head, os);
+
+}
+static void
+print_statement(s, os)
+lang_statement_union_type *s;
+lang_output_section_statement_type *os;
+{
+ while (s) {
+ switch (s->header.type) {
+ case lang_wild_statement_enum:
+ print_wild_statement(&s->wild_statement, os);
+ break;
+ default:
+ printf("Fail with %d\n",s->header.type);
+ FAIL();
+ break;
+ case lang_address_statement_enum:
+ printf("address\n");
+ break;
+ case lang_common_statement_enum:
+ print_common_statement();
+ break;
+ case lang_object_symbols_statement_enum:
+ printf("object symbols\n");
+ break;
+ case lang_fill_statement_enum:
+ print_fill_statement(&s->fill_statement);
+ break;
+ case lang_data_statement_enum:
+ print_data_statement(&s->data_statement);
+ break;
+
+
+ case lang_input_section_enum:
+ print_input_section(&s->input_section);
+ break;
+ case lang_padding_statement_enum:
+ print_padding_statement(&s->padding_statement);
+ break;
+ case lang_output_section_statement_enum:
+ print_output_section_statement(&s->output_section_statement);
+ break;
+ case lang_assignment_statement_enum:
+ print_assignment(&s->assignment_statement,
+ os);
+ break;
+
+
+ case lang_target_statement_enum:
+ printf("TARGET(%s)\n", s->target_statement.target);
+ break;
+ case lang_output_statement_enum:
+ printf("OUTPUT(%s)\n", s->output_statement.name);
+ break;
+ case lang_input_statement_enum:
+ print_input_statement(&s->input_statement);
+ break;
+ case lang_afile_asection_pair_statement_enum:
+ FAIL();
+ break;
+ }
+ s = s->next;
+ }
+}
+
+
+static void
+print_statements()
+{
+ print_statement(statement_list.head,
+ (lang_output_section_statement_type *)NULL);
+}
+
+static bfd_vma
+insert_pad(this_ptr, fill, power, output_section_statement, dot)
+lang_statement_union_type **this_ptr;
+fill_type fill;
+unsigned int power;
+asection * output_section_statement;
+bfd_vma dot;
+{
+ /* Align this section first to the
+ input sections requirement, then
+ to the output section's requirement.
+ If this alignment is > than any seen before,
+ then record it too. Perform the alignment by
+ inserting a magic 'padding' statement.
+ */
+
+ unsigned int alignment_needed = align_power(dot, power) - dot;
+
+ if (alignment_needed != 0)
+ {
+ lang_statement_union_type *new =
+ (lang_statement_union_type *)
+ ldmalloc(sizeof(lang_padding_statement_type));
+ /* Link into existing chain */
+ new->header.next = *this_ptr;
+ *this_ptr = new;
+ new->header.type = lang_padding_statement_enum;
+ new->padding_statement.output_section = output_section_statement;
+ new->padding_statement.output_offset =
+ dot - output_section_statement->vma;
+ new->padding_statement.fill = fill;
+ new->padding_statement.size = alignment_needed;
+ }
+
+
+ /* Remember the most restrictive alignment */
+ if (power > output_section_statement->alignment_power) {
+ output_section_statement->alignment_power = power;
+ }
+ output_section_statement->size += alignment_needed;
+ return alignment_needed + dot;
+
+}
+
+/*
+ size_common runs run though each global symboxl, and works
+ out how big the common section will be.
+ */
+
+static bfd_vma
+size_common(output_section_statement, this_ptr, dot)
+lang_output_section_statement_type *output_section_statement;
+lang_statement_union_type **this_ptr;
+bfd_vma dot;
+{
+ extern ldsym_type *symbol_head;
+ ldsym_type *sp;
+ /* Make sure that each symbol is only defined once.
+ Allocate common symbols
+ Make the ref chain point to the defining asymbol.
+ */
+ /* Now, for each symbol, verify that it is defined globally at most once.
+ Put the global value into the symbol entry.
+ Common symbols are allocated here, in the BSS section.
+ Each defined symbol is given a '->defined' field
+ which is the correct N_ code for its definition,
+ except in the case of common symbols with -r.
+ Then make all the references point at the symbol entry
+ instead of being chained together. */
+
+
+ common_section.name = output_section_statement->bfd_section->name;
+ common_section.output_section = output_section_statement->bfd_section;
+ common_section.output_offset =
+ dot - output_section_statement->bfd_section->vma;
+ if (config.relocateable_output == false ||
+ command_line.force_common_definition== true) {
+ dot = insert_pad(this_ptr,
+ 0x0, 4, output_section_statement->bfd_section, dot);
+
+ for (sp = symbol_head; sp != (ldsym_type *)NULL; sp = sp->next)
+ {
+ /* Attatch this symbol to the correct output section*/
+
+ /* Allocate as common if wanted */
+
+ if (sp->scoms_chain )
+
+ {
+ unsigned long com = (*(sp->scoms_chain))->value;
+ /* Work out what alignment this common item s
+ hould be put on. Anything < int is int aligned,
+ anything bigger is self aligned,
+ up to the restriction of the machine */
+
+ unsigned int align = sizeof(int);
+
+ /* Round up size of object to nearest int */
+ com = ALIGN(com, sizeof(int));
+ /* See what alignment is necessary -*/
+ if (com) {
+ while ((com & align)==0) align <<=1;
+ /* FIXME */
+ if (align > 8) {
+ align = 8;
+ }
+ }
+ dot = ALIGN(dot, align);
+
+
+ /* Transmogrify this from a common symbol
+ into a definition of a symbol in common
+ */
+ sp->sdefs_chain = sp->scoms_chain;
+
+ {
+ asymbol *com_ptr = *(sp->sdefs_chain);
+
+ sp->scoms_chain = (asymbol **)NULL;
+ commons_pending--;
+ /* Assign address, but keep section relative */
+
+ /* Force the symbol to belong in the bss section */
+ com_ptr->flags = BSF_EXPORT | BSF_GLOBAL ;
+ com_ptr->section = &common_section;
+ common_section.size += com;
+ if (write_map)
+ {
+ printf ("Allocating common %s: %lx at %lx\n",
+ sp->name,
+ com,
+ com_ptr->value);
+ }
+ com_ptr->value = common_section.size;
+ }
+ }
+ }
+ }
+ if (dot >
+ (common_section.output_section->vma +
+ common_section.output_section->size)) {
+ common_section.output_section->size =
+ dot - common_section.output_section->vma;
+ }
+ return dot + common_section.size;
+}
+
+static bfd_vma
+size_input_section( this_ptr, output_section_statement, fill, dot)
+lang_statement_union_type **this_ptr;
+lang_output_section_statement_type*output_section_statement;
+unsigned short fill;
+bfd_vma dot;
+{
+ lang_input_section_type *is = &((*this_ptr)->input_section);
+ asection *i = is->section;
+
+ dot = insert_pad(this_ptr, fill, i->alignment_power,
+ output_section_statement->bfd_section, dot);
+
+ /* remember the largest size so we can malloc the largest area */
+ /* needed for the output stage */
+ if (i->size > largest_section) {
+ largest_section = i->size;
+ }
+
+ /* Remember where in the output section this input section goes */
+ i->output_offset = dot - output_section_statement->bfd_section->vma;
+
+ /* Mark how big the output section must be to contain this now */
+ dot += i->size;
+ output_section_statement->bfd_section->size =
+ dot - output_section_statement->bfd_section->vma;
+
+
+ return dot ;
+}
+
+
+/* Work out the size of the output sections
+ from the sizes of the input sections */
+static bfd_vma
+lang_size_sections(s, output_section_statement, prev, fill, dot)
+lang_statement_union_type *s;
+lang_output_section_statement_type * output_section_statement;
+lang_statement_union_type **prev;
+unsigned short fill;
+bfd_vma dot;
+{
+ /* Size up the sections from their constituent parts */
+ for (; s != (lang_statement_union_type *)NULL ; s = s->next)
+ {
+ switch (s->header.type) {
+ case lang_output_section_statement_enum:
+ {
+ bfd_vma after;
+ lang_output_section_statement_type *os =
+ &(s->output_section_statement);
+ /* The start of a section */
+
+ if (os->addr_tree == (etree_type *)NULL) {
+ /* No address specified for this section, get one
+ from the region specification
+ */
+ if (os->region == (lang_memory_region_type *)NULL) {
+ os->region = lang_memory_region_lookup("*default*");
+ }
+ dot = os->region->current;
+ }
+ else {
+ etree_value_type r ;
+ r = exp_fold_tree(os->addr_tree,
+ (lang_output_section_statement_type *)NULL,
+ lang_allocating_phase_enum,
+ dot, &dot);
+ if (r.valid == false) {
+ info("%F%S: non constant address expression for section %s\n",
+ os->name);
+ }
+ dot = r.value;
+ }
+ /* The section starts here */
+ /* First, align to what the section needs */
+
+ dot = align_power(dot, os->bfd_section->alignment_power);
+ os->bfd_section->vma = dot;
+ os->bfd_section->output_offset = 0;
+
+ (void) lang_size_sections(os->children.head, os, &os->children.head,
+ os->fill, dot);
+ /* Ignore the size of the input sections, use the vma and size to */
+ /* align against */
+
+
+ after = ALIGN(os->bfd_section->vma +
+ os->bfd_section->size,
+ os->block_value) ;
+
+
+ os->bfd_section->size = after - os->bfd_section->vma;
+ dot = os->bfd_section->vma + os->bfd_section->size;
+ os->processed = true;
+
+ /* Replace into region ? */
+ if (os->addr_tree == (etree_type *)NULL
+ && os->region !=(lang_memory_region_type*)NULL ) {
+ os->region->current = dot;
+ }
+ }
+
+ break;
+
+ case lang_data_statement_enum:
+ {
+ unsigned int size;
+ s->data_statement.output_vma = dot;
+ s->data_statement.output_section =
+ output_section_statement->bfd_section;
+
+ switch (s->data_statement.type) {
+ case LONG:
+ size = LONG_SIZE;
+ break;
+ case SHORT:
+ size = SHORT_SIZE;
+ break;
+ case BYTE:
+ size = BYTE_SIZE;
+ break;
+
+ }
+ dot += size;
+ output_section_statement->bfd_section->size += size;
+ }
+ break;
+
+ case lang_wild_statement_enum:
+
+ dot = lang_size_sections(s->wild_statement.children.head,
+ output_section_statement,
+ &s->wild_statement.children.head,
+
+ fill, dot);
+
+ break;
+
+ case lang_object_symbols_statement_enum:
+ create_object_symbols = output_section_statement;
+ break;
+ case lang_output_statement_enum:
+
+ case lang_target_statement_enum:
+ break;
+ case lang_common_statement_enum:
+ dot = size_common(output_section_statement, prev, dot);
+
+ break;
+
+ case lang_input_section_enum:
+ dot = size_input_section(prev,
+ output_section_statement,
+ output_section_statement->fill, dot);
+ break;
+ case lang_input_statement_enum:
+ break;
+ case lang_fill_statement_enum:
+ fill = s->fill_statement.fill;
+ break;
+ case lang_assignment_statement_enum:
+ {
+ bfd_vma newdot = dot;
+ exp_fold_tree(s->assignment_statement.exp,
+ output_section_statement,
+ lang_allocating_phase_enum,
+ dot,
+ &newdot);
+
+ if (newdot != dot)
+ /* We've been moved ! so insert a pad */
+ {
+ lang_statement_union_type *new =
+ (lang_statement_union_type *)
+ ldmalloc(sizeof(lang_padding_statement_type));
+ /* Link into existing chain */
+ new->header.next = *prev;
+ *prev = new;
+ new->header.type = lang_padding_statement_enum;
+ new->padding_statement.output_section =
+ output_section_statement->bfd_section;
+ new->padding_statement.output_offset =
+ dot - output_section_statement->bfd_section->vma;
+ new->padding_statement.fill = fill;
+ new->padding_statement.size = newdot - dot;
+ output_section_statement->bfd_section->size +=
+ new->padding_statement.size;
+ dot = newdot;
+ }
+ }
+
+ break;
+ case lang_padding_statement_enum:
+ FAIL();
+ break;
+ default:
+ FAIL();
+ break;
+ case lang_address_statement_enum:
+ break;
+ }
+ prev = &s->header.next;
+ }
+ return dot;
+}
+
+
+static bfd_vma
+lang_do_assignments(s, output_section_statement, fill, dot)
+lang_statement_union_type *s;
+lang_output_section_statement_type * output_section_statement;
+unsigned short fill;
+bfd_vma dot;
+{
+
+ for (; s != (lang_statement_union_type *)NULL ; s = s->next)
+ {
+ switch (s->header.type) {
+ case lang_output_section_statement_enum:
+ {
+ lang_output_section_statement_type *os =
+ &(s->output_section_statement);
+ dot = os->bfd_section->vma;
+ (void) lang_do_assignments(os->children.head, os, os->fill, dot);
+ dot = os->bfd_section->vma + os->bfd_section->size;
+ }
+ break;
+ case lang_wild_statement_enum:
+
+ dot = lang_do_assignments(s->wild_statement.children.head,
+ output_section_statement,
+ fill, dot);
+
+ break;
+
+ case lang_object_symbols_statement_enum:
+ case lang_output_statement_enum:
+ case lang_target_statement_enum:
+ case lang_common_statement_enum:
+ break;
+ case lang_data_statement_enum:
+ {
+ etree_value_type value ;
+ value = exp_fold_tree(s->data_statement.exp,
+ 0, lang_final_phase_enum, dot, &dot);
+ s->data_statement.value = value.value;
+ if (value.valid == false) info("%F%P: Invalid data statement\n");
+ }
+ switch (s->data_statement.type) {
+ case LONG:
+ dot += LONG_SIZE;
+ break;
+ case SHORT:
+ dot += SHORT_SIZE;
+ break;
+ case BYTE:
+ dot += BYTE_SIZE;
+ break;
+ }
+ break;
+ case lang_input_section_enum:
+ {
+ asection *in = s->input_section.section;
+ dot += in->size;
+ }
+ break;
+
+ case lang_input_statement_enum:
+ break;
+ case lang_fill_statement_enum:
+ fill = s->fill_statement.fill;
+ break;
+ case lang_assignment_statement_enum:
+ {
+ exp_fold_tree(s->assignment_statement.exp,
+ output_section_statement,
+ lang_final_phase_enum,
+ dot,
+ &dot);
+ }
+
+ break;
+ case lang_padding_statement_enum:
+ dot += s->padding_statement.size;
+ break;
+ default:
+ FAIL();
+ break;
+ case lang_address_statement_enum:
+ break;
+ }
+
+ }
+ return dot;
+}
+
+
+
+static void lang_relocate_globals()
+{
+
+ /*
+ Each ldsym_type maintains a chain of pointers to asymbols which
+ references the definition. Replace each pointer to the referenence
+ with a pointer to only one place, preferably the definition. If
+ the defintion isn't available then the common symbol, and if
+ there isn't one of them then choose one reference.
+ */
+
+ FOR_EACH_LDSYM(lgs) {
+ asymbol *it;
+ if (lgs->sdefs_chain) {
+ it = *(lgs->sdefs_chain);
+ }
+ else if (lgs->scoms_chain != (asymbol **)NULL) {
+ it = *(lgs->scoms_chain);
+ }
+ else if (lgs->srefs_chain != (asymbol **)NULL) {
+ it = *(lgs->srefs_chain);
+ }
+ else {
+ FAIL();
+ }
+ if (it != (asymbol *)NULL)
+ {
+ asymbol **ptr= lgs->srefs_chain;
+
+ while (ptr != (asymbol **)NULL) {
+ asymbol *ref = *ptr;
+ *ptr = it;
+ ptr = (asymbol **)(ref->udata);
+ }
+ }
+ }
+}
+
+
+
+/* now that all the jiggery pokery is finished, copy important data from
+ * out internal form to the bfd way. Also create a section
+ * for each dummy file
+ */
+
+static void
+lang_create_output_section_statements()
+{
+ lang_statement_union_type*os;
+ for (os = lang_output_section_statement.head;
+ os != (lang_statement_union_type*)NULL;
+ os = os->output_section_statement.next) {
+ lang_output_section_statement_type *s =
+ &os->output_section_statement;
+ init_os(s);
+ }
+ script_file->the_bfd->sections = output_bfd->sections;
+}
+
+static void
+lang_finish()
+{
+ ldsym_type *lgs;
+
+ if (entry_symbol == (char *)NULL) {
+ /* No entry has been specified, look for start */
+ entry_symbol = "start";
+ }
+ lgs = ldsym_get_soft(entry_symbol);
+ if (lgs && lgs->sdefs_chain) {
+ asymbol *sy = *(lgs->sdefs_chain);
+ /* We can set the entry address*/
+ bfd_set_start_address(output_bfd,
+ outside_symbol_address(sy));
+
+ }
+ else {
+ /* Can't find anything reasonable,
+ use the first address in the text section
+ */
+ asection *ts = bfd_get_section_by_name(output_bfd, ".text");
+ if (ts) {
+ bfd_set_start_address(output_bfd, ts->vma);
+ }
+ }
+}
+
+/* By now we know the target architecture, and we may have an */
+/* ldfile_output_machine_name */
+static void
+lang_check()
+{
+ lang_statement_union_type *file;
+
+
+ for (file = file_chain.head;
+ file != (lang_statement_union_type *)NULL;
+ file=file->input_statement.next)
+ {
+ /* Inspect the architecture and ensure we're linking like
+ with like
+ */
+
+ if (bfd_arch_compatible( file->input_statement.the_bfd,
+ output_bfd,
+ &ldfile_output_architecture,
+ &ldfile_output_machine)) {
+ bfd_set_arch_mach(output_bfd,
+ ldfile_output_architecture, ldfile_output_machine);
+ }
+ else {
+ enum bfd_architecture this_architecture =
+ bfd_get_architecture(file->input_statement.the_bfd);
+ unsigned long this_machine =
+ bfd_get_machine(file->input_statement.the_bfd);
+
+ info("%I: architecture %s",
+ file,
+ bfd_printable_arch_mach(this_architecture, this_machine));
+ info(" incompatible with output %s\n",
+ bfd_printable_arch_mach(ldfile_output_architecture,
+ ldfile_output_machine));
+ ldfile_output_architecture = this_architecture;
+ ldfile_output_machine = this_machine;
+ bfd_set_arch_mach(output_bfd,
+ ldfile_output_architecture,
+ ldfile_output_machine);
+
+
+ }
+ }
+}
+
+
+/*
+ * run through all the global common symbols and tie them
+ * to the output section requested.
+ */
+
+static void
+lang_common()
+{
+ ldsym_type *lgs;
+ if (config.relocateable_output == false ||
+ command_line.force_common_definition== true) {
+ for (lgs = symbol_head;
+ lgs != (ldsym_type *)NULL;
+ lgs=lgs->next)
+ {
+ asymbol *com ;
+ size_t size;
+ size_t align;
+ if (lgs->scoms_chain != (asymbol **)NULL) {
+
+ com = *(lgs->scoms_chain);
+ size = com->value;
+ align = sizeof(int);
+ /* Round up size of object to nearest int */
+ size = ALIGN(size, sizeof(int));
+ /* Force alignment */
+ if (size) {
+ while ((size & align)==0) align<<=1;
+ if (align > 8) {
+ align = 8;
+ }
+ }
+ /* Change from a common symbol into a definition of
+ a symbol */
+ lgs->sdefs_chain = lgs->scoms_chain;
+ lgs->scoms_chain = (asymbol **)NULL;
+ commons_pending--;
+ /* Point to the correct common section */
+ com->section =
+ ((lang_input_statement_type *)
+ (com->the_bfd->usrdata))->common_section;
+ /* Fix the size of the common section */
+
+
+ com->flags = BSF_EXPORT | BSF_GLOBAL;
+
+ if (write_map)
+ {
+ printf ("Allocating common %s: %x at %x\n",
+ lgs->name,
+ (unsigned) size,
+ (unsigned) com->section->size);
+ }
+ com->value = com->section->size;
+ com->section->size += size;
+ }
+ }
+ }
+}
+
+/*
+run through the input files and ensure that every input
+section has somewhere to go. If one is found without
+a destination then create an input request and place it
+into the statement tree.
+*/
+
+static void lang_place_orphans()
+{
+ lang_input_statement_type *file;
+ for (file = (lang_input_statement_type*)file_chain.head;
+ file != (lang_input_statement_type*)NULL;
+ file = (lang_input_statement_type*)file->next) {
+ asection *s;
+ for (s = file->the_bfd->sections;
+ s != (asection *)NULL;
+ s = s->next) {
+ if ( s->output_section == (asection *)NULL) {
+ /* This section of the file is not attatched, root
+ around for a sensible place for it to go */
+
+ if (file->common_section == s) {
+ /* This is a lonely common section which must
+ have come from an archive. We attatch to the
+ section with the wildcard */
+ wild_doit(&default_common_section->children, s,
+ default_common_section, file);
+ }
+ else {
+ lang_output_section_statement_type *os =
+ lang_output_section_statement_lookup(s->name);
+
+ wild_doit(&os->children, s, os, file);
+ }
+ }
+ }
+
+ }
+}
+
+
+/*
+ * phase_2
+ *
+ * peformed after every file has been opened and symbols read
+ */
+static void
+lang_phase_2()
+{
+ lang_init2();
+
+ lang_create_output_section_statements();
+ lang_open_input(statement_list.head, (char *)NULL,
+ ( lang_output_section_statement_type *)NULL);
+ lang_place_orphans();
+ lang_common();
+
+ ldemul_before_allocation();
+
+ lang_size_sections(statement_list.head,
+ (lang_output_section_statement_type *)NULL,
+ &(statement_list.head), 0, (bfd_vma)0);
+ ldemul_after_allocation();
+ /* Do it once again now that we know the sizes of everything */
+
+ lang_do_assignments(statement_list.head,
+ (lang_output_section_statement_type *)NULL,
+ 0, (bfd_vma)0);
+
+
+
+ lang_check();
+
+ lang_relocate_globals();
+
+
+ lang_finish();
+}
+
+
+
+
+void
+lang_set_flags(ptr, flags)
+lang_section_flags_type *ptr;
+char *flags;
+{
+ boolean state = true;
+ ptr->flag_read = false;
+ ptr->flag_write = false;
+ ptr->flag_executable = false;
+ ptr->flag_loadable= false;
+ while (*flags)
+ {
+ if (*flags == '!') {
+ state = false;
+ flags++;
+ }
+ else state = true;
+ switch (*flags) {
+ case 'R':
+ ptr->flag_read = state;
+ break;
+ case 'W':
+ ptr->flag_write = state;
+ break;
+ case 'X':
+ ptr->flag_executable= state;
+ break;
+ case 'L':
+ ptr->flag_loadable= state;
+ break;
+ default:
+ info("%P%F illegal syntax in flags\n");
+ break;
+ }
+ flags++;
+ }
+}
+
+
+
+void
+lang_for_each_file(func)
+void (*func)();
+{
+ lang_input_statement_type *f;
+ for (f = (lang_input_statement_type *)file_chain.head;
+ f != (lang_input_statement_type *)NULL;
+ f = (lang_input_statement_type *)f->next)
+ {
+ func(f);
+ }
+}
+
+
+void
+lang_for_each_input_section(func)
+void (*func)();
+{
+ lang_input_statement_type *f;
+ for (f = (lang_input_statement_type *)file_chain.head;
+ f != (lang_input_statement_type *)NULL;
+ f = (lang_input_statement_type *)f->next)
+ {
+ asection *s;
+ for (s = f->the_bfd->sections;
+ s != (asection *)NULL;
+ s = s->next) {
+ func(f->the_bfd, s);
+ }
+ }
+}
+
+
+
+void
+ldlang_add_file(entry)
+lang_input_statement_type *entry;
+{
+ lang_has_input_file = true;
+ lang_statement_append(&file_chain,
+ (lang_statement_union_type *)entry,
+ &entry->next);
+}
+
+
+
+void
+lang_add_output(name)
+char *name;
+{
+ lang_output_statement_type *new = new_stat(lang_output_statement,
+ stat_ptr);
+ new->name = name;
+ had_output_filename = true;
+}
+
+
+static lang_output_section_statement_type *current_section;
+
+void
+lang_enter_output_section_statement(output_section_statement_name,
+address_exp,
+block_value)
+char *output_section_statement_name;
+etree_type *address_exp;
+bfd_vma block_value;
+{
+ lang_output_section_statement_type *os;
+ current_section =
+ os =
+ lang_output_section_statement_lookup(output_section_statement_name);
+
+
+ /* Add this statement to tree */
+ /* add_statement(lang_output_section_statement_enum,
+ output_section_statement);*/
+ /* Make next things chain into subchain of this */
+
+ if (os->addr_tree ==
+ (etree_type *)NULL) {
+ os->addr_tree =
+ address_exp;
+ }
+ os->block_value = block_value;
+ stat_ptr = & os->children;
+
+}
+
+
+void
+lang_final()
+{
+ if (had_output_filename == false) {
+ lang_add_output("a.out");
+ }
+
+
+}
+
+
+
+
+
+asymbol *create_symbol(name, flags, section)
+char *name;
+flagword flags;
+asection *section;
+{
+ extern lang_input_statement_type *script_file;
+ asymbol **def_ptr = (asymbol **)ldmalloc(sizeof(asymbol **));
+ /* Add this definition to script file */
+ asymbol *def = (asymbol *)bfd_make_empty_symbol(script_file->the_bfd);
+ def->name = name;
+ def->udata = 0;
+ def->flags = flags;
+ def->section = section;
+
+ *def_ptr = def;
+ Q_enter_global_ref(def_ptr);
+ return def;
+}
+
+
+void
+lang_process()
+{
+ lang();
+ lang_phase_2();
+}
+
+
+/* EXPORTED TO YACC */
+void
+lang_section_start(name, address)
+char *name;
+etree_type *address;
+{
+ lang_address_statement_type *ad =new_stat(lang_address_statement, stat_ptr);
+ ad->section_name = name;
+ ad->address = address;
+}
+void lang_add_entry(name)
+char *name;
+{
+ entry_symbol = name;
+}
+
+void
+lang_add_target(name)
+char *name;
+{
+ lang_target_statement_type *new = new_stat(lang_target_statement,
+ stat_ptr);
+ new->target = name;
+
+}
+void
+lang_add_wild(section_name, filename)
+char *section_name;
+char *filename;
+{
+ lang_wild_statement_type *new = new_stat(lang_wild_statement,
+ stat_ptr);
+
+ if (section_name != (char *)NULL && strcmp(section_name,"COMMON") == 0)
+ {
+ placed_commons = true;
+ }
+ new->section_name = section_name;
+ new->filename = filename;
+ lang_list_init(&new->children);
+}
+
+void
+lang_add_map(name)
+char *name;
+{
+ while (*name) {
+ switch (*name) {
+ case 'F':
+ map_option_f = true;
+ break;
+ }
+ name++;
+ }
+}
+
+void lang_add_fill(exp)
+int exp;
+{
+ lang_fill_statement_type *new = new_stat(lang_fill_statement,
+ stat_ptr);
+ new->fill = exp;
+}
+
+void lang_add_data(type, exp)
+int type;
+union etree_union *exp;
+{
+
+ lang_data_statement_type *new = new_stat(lang_data_statement,
+ stat_ptr);
+ new->exp = exp;
+ new->type = type;
+
+}
+void
+lang_add_assignment(exp)
+etree_type *exp;
+{
+ lang_assignment_statement_type *new = new_stat(lang_assignment_statement,
+ stat_ptr);
+ new->exp = exp;
+}
+
+void
+lang_add_attribute(attribute)
+enum statement_enum attribute;
+{
+ new_statement(attribute, sizeof(lang_statement_union_type),stat_ptr);
+}
+
+
+
+void
+lang_startup(name)
+char *name;
+{
+ if (startup_file != (char *)NULL) {
+ info("%P%FMultiple STARTUP files\n");
+ }
+ first_file->filename = name;
+ first_file->local_sym_name = name;
+
+ startup_file= name;
+}
+void
+lang_float(maybe)
+boolean maybe;
+{
+ lang_float_flag = maybe;
+}
+
+void
+lang_leave_output_section_statement(fill, memspec)
+bfd_vma fill;
+char *memspec;
+{
+ current_section->fill = fill;
+ current_section->region = lang_memory_region_lookup(memspec);
+ stat_ptr = &statement_list;
+}
+
+void
+lang_abs_symbol_at_end_of(section, name)
+char *section;
+char *name;
+{
+ extern bfd *output_bfd;
+ extern asymbol *create_symbol();
+ asection *s = bfd_get_section_by_name(output_bfd, section);
+ /* Add a symbol called _end */
+ asymbol *def = create_symbol(name,
+ BSF_GLOBAL | BSF_EXPORT |
+ BSF_ABSOLUTE,
+ (asection *)NULL);
+ if (s != (asection *)NULL) {
+ def->value = s->vma + s->size;
+ }
+ else {
+ def->value = 0;
+ }
+}
+
+void
+lang_statement_append(list, element, field)
+lang_statement_list_type *list;
+lang_statement_union_type *element;
+lang_statement_union_type **field;
+{
+ *(list->tail) = element;
+ list->tail = field;
+}
+
+
+static void
+lang_for_each_statement_worker(func, s)
+void (*func)();
+lang_statement_union_type *s;
+{
+ for (; s != (lang_statement_union_type *)NULL ; s = s->next)
+ {
+ func(s);
+
+ switch (s->header.type) {
+ case lang_output_section_statement_enum:
+ lang_for_each_statement_worker
+ (func,
+ s->output_section_statement.children.head);
+ break;
+ case lang_wild_statement_enum:
+ lang_for_each_statement_worker
+ (func,
+ s->wild_statement.children.head);
+ break;
+ case lang_data_statement_enum:
+ case lang_object_symbols_statement_enum:
+ case lang_output_statement_enum:
+ case lang_target_statement_enum:
+ case lang_common_statement_enum:
+ case lang_input_section_enum:
+ case lang_input_statement_enum:
+ case lang_fill_statement_enum:
+ case lang_assignment_statement_enum:
+ case lang_padding_statement_enum:
+ case lang_address_statement_enum:
+ break;
+ default:
+ FAIL();
+ break;
+ }
+ }
+}
+
+void lang_for_each_statement(func)
+void (*func)();
+{
+ lang_for_each_statement_worker(func,
+ statement_list.head);
+
+}