/* Linker command language support.
- Copyright 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1991, 92, 93, 94 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
#include "bfd.h"
#include "sysdep.h"
+#include "libiberty.h"
#include "bfdlink.h"
#include "ld.h"
/* LOCALS */
static struct obstack stat_obstack;
-#define obstack_chunk_alloc ldmalloc
+#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
static CONST char *startup_file;
static lang_statement_list_type input_file_chain;
lang_statement_union_type *s));
static lang_input_statement_type *new_afile
PARAMS ((const char *name, lang_input_file_enum_type file_type,
- const char *target));
+ const char *target, boolean add_to_list));
static void print_flags PARAMS ((int *ignore_flags));
static void init_os PARAMS ((lang_output_section_statement_type *s));
static void wild_doit PARAMS ((lang_statement_list_type *ptr,
lang_input_statement_type *file,
lang_output_section_statement_type *output));
static lang_input_statement_type *lookup_name PARAMS ((const char *name));
+static void load_symbols PARAMS ((lang_input_statement_type *entry));
static void wild PARAMS ((lang_wild_statement_type *s,
const char *section, const char *file,
const char *target,
PARAMS ((lang_assignment_statement_type *assignment,
lang_output_section_statement_type *output_section));
static void print_input_statement PARAMS ((lang_input_statement_type *statm));
-static void print_symbol PARAMS ((asymbol *q));
static void print_input_section PARAMS ((lang_input_section_type *in));
static void print_fill_statement PARAMS ((lang_fill_statement_type *fill));
static void print_data_statement PARAMS ((lang_data_statement_type *data));
+static void print_reloc_statement PARAMS ((lang_reloc_statement_type *reloc));
static void print_padding_statement PARAMS ((lang_padding_statement_type *s));
static void print_wild_statement
PARAMS ((lang_wild_statement_type *w,
PARAMS ((lang_statement_union_type **this_ptr,
lang_output_section_statement_type *output_section_statement,
fill_type fill, bfd_vma dot, boolean relax));
-static bfd_vma lang_size_sections
- PARAMS ((lang_statement_union_type *s,
- lang_output_section_statement_type *output_section_statement,
- lang_statement_union_type **prev, fill_type fill,
- bfd_vma dot, boolean relax));
static bfd_vma lang_do_assignments
PARAMS ((lang_statement_union_type * s,
lang_output_section_statement_type *output_section_statement,
lang_statement_list_type file_chain =
{0};
CONST char *entry_symbol = 0;
-bfd_size_type largest_section = 0;
boolean lang_has_input_file = false;
boolean had_output_filename = false;
boolean lang_float_flag = false;
etree_type *base; /* Relocation base - or null */
-#ifdef __STDC__
+#if defined(__STDC__) || defined(ALMOST_STDC)
#define cat(a,b) a##b
#else
#define cat(a,b) a/**/b
s->wild_statement.children.head);
break;
case lang_data_statement_enum:
+ case lang_reloc_statement_enum:
case lang_object_symbols_statement_enum:
case lang_output_statement_enum:
case lang_target_statement_enum:
*/
static lang_input_statement_type *
-new_afile (name, file_type, target)
+new_afile (name, file_type, target, add_to_list)
CONST char *name;
lang_input_file_enum_type file_type;
CONST char *target;
+ boolean add_to_list;
{
+ lang_input_statement_type *p;
- lang_input_statement_type *p = new_stat (lang_input_statement,
- stat_ptr);
+ if (add_to_list)
+ p = new_stat (lang_input_statement, stat_ptr);
+ else
+ {
+ p = ((lang_input_statement_type *)
+ stat_alloc (sizeof (lang_input_statement_type)));
+ p->header.next = NULL;
+ }
lang_has_input_file = true;
p->target = target;
p->is_archive = true;
p->filename = name;
p->real = true;
- p->local_sym_name = concat ("-l", name, "");
+ p->local_sym_name = concat ("-l", name, (const char *) NULL);
p->just_syms_flag = false;
p->search_dirs_flag = true;
break;
- case lang_input_file_is_search_file_enum:
case lang_input_file_is_marker_enum:
+ p->filename = name;
+ p->is_archive = false;
+ p->real = false;
+ p->local_sym_name = name;
+ p->just_syms_flag = false;
+ p->search_dirs_flag = true;
+ break;
+ case lang_input_file_is_search_file_enum:
p->filename = name;
p->is_archive = false;
p->real = true;
default:
FAIL ();
}
+ p->the_bfd = (bfd *) NULL;
p->asymbols = (asymbol **) NULL;
p->superfile = (lang_input_statement_type *) NULL;
p->next_real_file = (lang_statement_union_type *) NULL;
}
#endif
- return new_afile (name, file_type, target);
+ return new_afile (name, file_type, target, true);
}
/* Build enough state so that the parser can build its tree */
not define anything we need at the time, they won't have all their
symbols read. If we need them later, we'll have to redo it.
*/
-static
-lang_input_statement_type *
+static lang_input_statement_type *
lookup_name (name)
CONST char *name;
{
}
if (search == (lang_input_statement_type *) NULL)
- {
- /* 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, default_target);
- }
+ search = new_afile (name, lang_input_file_is_file_enum, default_target,
+ false);
/* If we have already added this file, or this file is not real
(FIXME: can that ever actually happen?) or the name is NULL
|| search->filename == (const char *) NULL)
return search;
- ldfile_open_file (search);
+ load_symbols (search);
+
+ return search;
+}
- if (bfd_check_format (search->the_bfd, bfd_object))
+/* Get the symbols for an input file. */
+
+static void
+load_symbols (entry)
+ lang_input_statement_type *entry;
+{
+ if (entry->loaded)
+ return;
+
+ ldfile_open_file (entry);
+
+ if (bfd_check_format (entry->the_bfd, bfd_object))
{
- ldlang_add_file (search);
+ ldlang_add_file (entry);
if (trace_files || trace_file_tries)
- info_msg ("%I\n", search);
+ info_msg ("%I\n", entry);
}
- else if (bfd_check_format (search->the_bfd, bfd_archive))
+ else if (bfd_check_format (entry->the_bfd, bfd_archive))
{
/* There is nothing to do here; the add_symbols routine will
call ldlang_add_file (via the add_archive_element callback)
for each element of the archive which is used. */
}
else
- einfo ("%F%B: file not recognized: %E\n", search->the_bfd);
+ einfo ("%F%B: file not recognized: %E\n", entry->the_bfd);
- if (bfd_link_add_symbols (search->the_bfd, &link_info) == false)
- einfo ("%F%B: could not read symbols: %E\n", search->the_bfd);
+ if (bfd_link_add_symbols (entry->the_bfd, &link_info) == false)
+ einfo ("%F%B: could not read symbols: %E\n", entry->the_bfd);
- search->loaded = true;
-
- return search;
+ entry->loaded = true;
}
static void
if (output == (bfd *) NULL)
{
- if (bfd_error == invalid_target)
+ if (bfd_get_error () == bfd_error_invalid_target)
{
einfo ("%P%F: target %s not found\n", output_target);
}
if (statement->input_statement.real == true)
{
statement->input_statement.target = current_target;
- lookup_name (statement->input_statement.filename);
+ load_symbols (&statement->input_statement);
}
break;
default:
case lang_input_section_enum:
case lang_object_symbols_statement_enum:
case lang_data_statement_enum:
+ case lang_reloc_statement_enum:
case lang_assignment_statement_enum:
case lang_padding_statement_enum:
break;
}
}
-static void
-print_symbol (q)
- asymbol * q;
+/* Print all the defined symbols for the abfd provided by in the supplied
+ section.
+*/
+
+static boolean
+print_one_symbol (hash_entry, ptr)
+struct bfd_link_hash_entry *hash_entry;
+PTR ptr;
{
- print_section ("");
- fprintf (config.map_file, " ");
- print_section ("");
- fprintf (config.map_file, " ");
- print_address (outside_symbol_address (q));
- fprintf (config.map_file, " %s", q->name ? q->name : " ");
- if (q->flags & BSF_WEAK)
- fprintf (config.map_file, " *weak*");
- print_nl ();
+ asection * sec = (asection *)ptr;
+
+ if (hash_entry->type == bfd_link_hash_defined)
+ {
+ if (sec == hash_entry->u.def.section) {
+ print_section ("");
+ fprintf (config.map_file, " ");
+ print_section ("");
+ fprintf (config.map_file, " ");
+ print_address (hash_entry->u.def.value + outside_section_address (sec));
+ fprintf (config.map_file, " %s", hash_entry->root.string);
+ print_nl ();
+ }
+ }
+
+ return true;
}
static void
lang_input_section_type * in;
{
asection *i = in->section;
- int size = i->reloc_done ?
- bfd_get_section_size_after_reloc (i) :
- bfd_get_section_size_before_reloc (i);
+ bfd_size_type size = i->_cooked_size != 0 ? i->_cooked_size : i->_raw_size;
if (size != 0)
{
fprintf (config.map_file, "(overhead %d bytes)", (int) bfd_alloc_size (abfd));
print_nl ();
- /* Find all the symbols in this file defined in this section */
-
- if (in->ifile->symbol_count)
- {
- asymbol **p;
-
- for (p = in->ifile->asymbols; *p; p++)
- {
- asymbol *q = *p;
-
- if (bfd_get_section (q) == i
- && (q->flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
- {
- print_symbol (q);
- }
- }
- }
+ /* Print all the symbols */
+ bfd_link_hash_traverse (link_info.hash, print_one_symbol, (PTR) i);
}
else
{
fprintf (config.map_file, "\n");
}
+/* Print a reloc statement. */
+
+static void
+print_reloc_statement (reloc)
+ lang_reloc_statement_type *reloc;
+{
+ print_section ("");
+ print_space ();
+ print_section ("");
+ print_space ();
+
+/* ASSERT(print_dot == data->output_vma);*/
+
+ print_address (reloc->output_vma + reloc->output_section->vma);
+ print_space ();
+ print_address (reloc->addend_value);
+ print_space ();
+
+ fprintf (config.map_file, "RELOC %s ", reloc->howto->name);
+
+ print_dot += bfd_get_reloc_size (reloc->howto);
+
+ exp_print_tree (reloc->addend_exp);
+
+ fprintf (config.map_file, "\n");
+}
static void
print_padding_statement (s)
case lang_data_statement_enum:
print_data_statement (&s->data_statement);
break;
+ case lang_reloc_statement_enum:
+ print_reloc_statement (&s->reloc_statement);
+ break;
case lang_input_section_enum:
print_input_section (&s->input_section);
break;
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. Only remember the size of sections
- which we will actually allocate */
- if ((i->flags & SEC_HAS_CONTENTS) != 0
- && (bfd_get_section_size_before_reloc (i) > largest_section))
- {
- largest_section = bfd_get_section_size_before_reloc (i);
- }
-
/* 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
*/
- if (relax)
- {
- dot += i->_cooked_size;
- }
+ if (i->_cooked_size != 0)
+ dot += i->_cooked_size;
else
- {
- dot += i->_raw_size;
- }
+ dot += i->_raw_size;
output_section_statement->bfd_section->_raw_size = dot - output_section_statement->bfd_section->vma;
}
else
return dot;
}
-/* Sizing happens in two passes, first pass we allocate worst case
- stuff. The second pass (if relaxing), we use what we learnt to
- change the size of some relocs from worst case to better
- */
-static boolean had_relax;
+/* This variable indicates whether bfd_relax_section should be called
+ again. */
-static bfd_vma
+static boolean relax_again;
+
+/* Set the sizes for all the output sections. */
+
+bfd_vma
lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
lang_statement_union_type * s;
lang_output_section_statement_type * output_section_statement;
/* The section starts here */
/* First, align to what the section needs */
+ if (os->section_alignment != -1)
+ dot = align_power (dot, os->section_alignment);
- dot = align_power (dot, os->bfd_section->alignment_power);
bfd_set_section_vma (0, os->bfd_section, dot);
if (os->load_base) {
}
break;
+ case lang_reloc_statement_enum:
+ {
+ int size;
+
+ s->reloc_statement.output_vma =
+ dot - output_section_statement->bfd_section->vma;
+ s->reloc_statement.output_section =
+ output_section_statement->bfd_section;
+ size = bfd_get_reloc_size (s->reloc_statement.howto);
+ dot += size;
+ output_section_statement->bfd_section->_raw_size += size;
+ }
+ break;
+
case lang_wild_statement_enum:
dot = lang_size_sections (s->wild_statement.children.head,
case lang_target_statement_enum:
break;
case lang_input_section_enum:
- if (relax)
{
- lang_input_section_type *is;
asection *i;
- is = &(*prev)->input_section;
- i = is->section;
-
- /* FIXME: The interface to bfd_relax_section should be changed
- to not require the generic symbols to be read. Changing
- this would require changing both b_out_relax_section and
- bfd_coff_relax16_section. */
- if (is->ifile->asymbols == (asymbol **) NULL)
+ i = (*prev)->input_section.section;
+ if (! relax)
+ i->_cooked_size = i->_raw_size;
+ else
{
- unsigned int symsize;
-
- symsize = get_symtab_upper_bound (i->owner);
- is->ifile->asymbols = (asymbol **) ldmalloc (symsize);
- is->ifile->symbol_count =
- bfd_canonicalize_symtab (i->owner, is->ifile->asymbols);
-
- /* The generic linker code in BFD requires that these
- symbols be stored in the outsymbols and symcount
- fields. When the bfd_relax_section is interface is
- fixed this should also be fixed. */
- i->owner->outsymbols = is->ifile->asymbols;
- i->owner->symcount = is->ifile->symbol_count;
- }
-
- if (bfd_relax_section (i->owner, i, &link_info, is->ifile->asymbols))
- had_relax = true;
- }
- else {
- (*prev)->input_section.section->_cooked_size =
- (*prev)->input_section.section->_raw_size ;
+ boolean again;
+ if (! bfd_relax_section (i->owner, i, &link_info, &again))
+ einfo ("%P%F: can't relax section: %E\n");
+ if (again)
+ relax_again = true;
+ }
+ dot = size_input_section (prev,
+ output_section_statement,
+ output_section_statement->fill,
+ dot, relax);
}
- dot = size_input_section (prev,
- output_section_statement,
- output_section_statement->fill,
- dot, relax);
break;
case lang_input_statement_enum:
break;
}
break;
+
+ case lang_padding_statement_enum:
+ /* If we are relaxing, and this is not the first pass, some
+ padding statements may have been inserted during previous
+ passes. We may have to move the padding statement to a new
+ location if dot has a different value at this point in this
+ pass than it did at this point in the previous pass. */
+ s->padding_statement.output_offset =
+ dot - output_section_statement->bfd_section->vma;
+ dot += s->padding_statement.size;
+ break;
+
default:
FAIL ();
break;
+
/* This can only get here when relaxing is turned on */
- case lang_padding_statement_enum:
case lang_address_statement_enum:
break;
break;
}
break;
+
+ case lang_reloc_statement_enum:
+ {
+ etree_value_type value;
+
+ value = exp_fold_tree (s->reloc_statement.addend_exp,
+ abs_output_section,
+ lang_final_phase_enum, dot, &dot);
+ s->reloc_statement.addend_value = value.value;
+ if (value.valid == false)
+ einfo ("%F%P: invalid reloc statement\n");
+ }
+ dot += bfd_get_reloc_size (s->reloc_statement.howto);
+ break;
+
case lang_input_section_enum:
{
asection *in = s->input_section.section;
- dot += bfd_get_section_size_before_reloc (in);
+ if (in->_cooked_size != 0)
+ dot += in->_cooked_size;
+ else
+ dot += in->_raw_size;
}
break;
/* Increase the size of the section. */
section->_raw_size += size;
- if (write_map && config.map_file != NULL)
+ if (config.map_file != NULL)
fprintf (config.map_file, "Allocating common %s: %lx at %lx %s\n",
h->root.string, (unsigned long) size,
(unsigned long) h->u.def.value, section->owner->filename);
;
*pp = entry->the_bfd;
entry->the_bfd->usrdata = (PTR) entry;
+ bfd_set_gp_size (entry->the_bfd, g_switch_value);
}
void
files. */
ldctor_build_sets ();
+ /* Size up the common data */
+ lang_common ();
+
/* Run through the contours of the script and attatch input sections
to the correct output sections
*/
/* Find any sections not attatched explicitly and handle them */
lang_place_orphans ();
- /* Size up the common data */
- lang_common ();
-
ldemul_before_allocation ();
-
-#if 0
- had_relax = true;
- while (had_relax)
- {
-
- had_relax = false;
-
- lang_size_sections (statement_list.head,
- (lang_output_section_statement_type *) NULL,
- &(statement_list.head), 0, (bfd_vma) 0, true);
- /* FIXME. Until the code in relax is fixed so that it only reads in
- stuff once, we cant iterate since there is no way for the linker to
- know what has been patched and what hasn't */
- break;
-
- }
-#endif
-
/* Now run around and relax if we can */
if (command_line.relax)
{
/* First time round is a trial run to get the 'worst case'
addresses of the objects if there was no relaxing. */
lang_size_sections (statement_list.head,
- (lang_output_section_statement_type *) NULL,
+ abs_output_section,
&(statement_list.head), 0, (bfd_vma) 0, false);
reset_memory_regions ();
- /* Do all the assignments, now that we know the final resting
- places of all the symbols. */
+ /* Keep relaxing until bfd_relax_section gives up. */
+ do
+ {
+ relax_again = false;
- lang_do_assignments (statement_list.head,
- abs_output_section,
- (fill_type) 0, (bfd_vma) 0);
+ /* Do all the assignments with our current guesses as to
+ section sizes. */
+ lang_do_assignments (statement_list.head,
+ abs_output_section,
+ (fill_type) 0, (bfd_vma) 0);
- /* Perform another relax pass - this time we know where the
- globals are, so can make better guess. */
- lang_size_sections (statement_list.head,
- (lang_output_section_statement_type *) NULL,
- &(statement_list.head), 0, (bfd_vma) 0, true);
+ /* Perform another relax pass - this time we know where the
+ globals are, so can make better guess. */
+ lang_size_sections (statement_list.head,
+ abs_output_section,
+ &(statement_list.head), 0, (bfd_vma) 0, true);
+ }
+ while (relax_again);
}
else
{
/* Final stuffs */
ldemul_finish ();
-
-#if 0
- /* DO NOT REENABLE THIS CALL. IF THIS CALL IS MADE, THE SUN4 LINKER
- CAN NOT BOOTSTRAP!! No, I don't know why, but don't change it
- unless you fix it. */
- /* Size up the sections. */
- lang_size_sections (statement_list.head,
- abs_output_section,
- &(statement_list.head), 0, (bfd_vma) 0, false);
-#endif
-
lang_finish ();
}
}
+/* Create a new reloc statement. RELOC is the BFD relocation type to
+ generate. HOWTO is the corresponding howto structure (we could
+ look this up, but the caller has already done so). SECTION is the
+ section to generate a reloc against, or NAME is the name of the
+ symbol to generate a reloc against. Exactly one of SECTION and
+ NAME must be NULL. ADDEND is an expression for the addend. */
+
+void
+lang_add_reloc (reloc, howto, section, name, addend)
+ bfd_reloc_code_real_type reloc;
+ const reloc_howto_type *howto;
+ asection *section;
+ const char *name;
+ union etree_union *addend;
+{
+ lang_reloc_statement_type *p = new_stat (lang_reloc_statement, stat_ptr);
+
+ p->reloc = reloc;
+ p->howto = howto;
+ p->section = section;
+ p->name = name;
+ p->addend_exp = addend;
+
+ p->addend_value = 0;
+ p->output_section = NULL;
+ p->output_vma = 0;
+}
+
void
lang_add_assignment (exp)
etree_type * exp;
}
first_file->filename = name;
first_file->local_sym_name = name;
+ first_file->real = true;
startup_file = name;
}