diff options
Diffstat (limited to 'ld/ldlang.c')
-rw-r--r-- | ld/ldlang.c | 2231 |
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); + +} |