#include "ldmain.h"
#include "ldsym.h"
#include "ldgram.h"
-
+#include "ldwarn.h"
#include "ldlang.h"
#include "ldexp.h"
#include "ldemul.h"
/* LOCALS */
static CONST char *startup_file;
static lang_statement_list_type input_file_chain;
+
+/* Points to the last statement in the .data section, so we can add
+ stuff to the data section without pain */
+static lang_statement_list_type end_of_data_section_statement_list;
+
+/* List of statements needed to handle consxtructors */
+static lang_statement_list_type constructor_list;
+
static boolean placed_commons = false;
static lang_output_section_statement_type *default_common_section;
static boolean map_option_f;
#define outside_symbol_address(q) ((q)->value + outside_section_address(q->section))
+static void EXFUN(lang_add_data,( int type , union etree_union *exp));
+
static void
DEFUN(print_size,(value),
size_t value)
func(s);
switch (s->header.type) {
+ case lang_constructors_statement_enum:
+ lang_for_each_statement_worker(func, constructor_list.head);
+ break;
case lang_output_section_statement_enum:
lang_for_each_statement_worker
(func,
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_constructors_statement_enum:
+ map_input_to_output_sections(constructor_list.head,
+ target,
+ output_section_statement);
+ break;
case lang_output_section_statement_enum:
map_input_to_output_sections(s->output_section_statement.children.head,
target,
{
while (s) {
switch (s->header.type) {
+ case lang_constructors_statement_enum:
+ printf("constructors:\n");
+print_statement(constructor_list.head, os);
+break;
+
case lang_wild_statement_enum:
print_wild_statement(&s->wild_statement, os);
break;
for (; s != (lang_statement_union_type *)NULL ; s = s->next)
{
switch (s->header.type) {
+
+
case lang_output_section_statement_enum:
{
bfd_vma after;
}
break;
-
+ case lang_constructors_statement_enum:
+ dot = lang_size_sections(constructor_list.head,
+ output_section_statement,
+ &s->wild_statement.children.head,
+ fill,
+ dot);
+ break;
+
case lang_data_statement_enum:
{
unsigned int size;
for (; s != (lang_statement_union_type *)NULL ; s = s->next)
{
switch (s->header.type) {
+ case lang_constructors_statement_enum:
+ dot = lang_do_assignments(constructor_list.head,
+ output_section_statement,
+ fill,
+ dot);
+ break;
+
case lang_output_section_statement_enum:
{
lang_output_section_statement_type *os =
}
if (it != (asymbol *)NULL)
{
- asymbol **ptr= lgs->srefs_chain;
+ asymbol **ptr = lgs->srefs_chain;;
+ if (lgs->flags & SYM_WARNING)
+ {
+ produce_warnings(lgs, it);
+ }
+ if (lgs->flags & SYM_INDIRECT)
+ {
+ do_indirect(lgs);
+ }
while (ptr != (asymbol **)NULL) {
asymbol *ref = *ptr;
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);*/
return def;
}
+/* run through the symbol table, find all the symbols which are
+ constructors and for each one, create statements to do something
+ like..
+
+ for
+ __CTOR_LIST__, foo
+
+ __CTOR_LIST__ = . ;
+ LONG(__CTOR_LIST_END - . / 4 - 2)
+ *(foo)
+ __CTOR_LIST_END= .
+
+ Put these statements onto a special list.
+
+*/
+
+typedef struct constructor_list
+{
+ldsym_type *sym;
+ struct constructor_list *next;
+} constructor_list_type;
+
+static constructor_list_type *constructor_name_list;
+
+void
+DEFUN(ldlang_add_constructor,(name),
+ldsym_type *name)
+{
+
+ constructor_list_type *next = constructor_name_list;
+
+ if (name->flags & SYM_CONSTRUCTOR) return;
+
+ next = (constructor_list_type *) ldmalloc(sizeof(constructor_list_type));
+ next->next= constructor_name_list;
+ next->sym= name;
+ name->flags |= SYM_CONSTRUCTOR;
+ constructor_name_list = next;
+}
+
+void
+DEFUN_VOID(find_constructors)
+{
+ lang_statement_list_type *old = stat_ptr;
+ constructor_list_type *p = constructor_name_list;
+ stat_ptr = & constructor_list;
+ lang_list_init(stat_ptr);
+ while (p != (constructor_list_type *)NULL)
+ {
+ /* Have we already done this one ? */
+ CONST char *name = p->sym->name;
+ int len = strlen(name);
+ char *end = ldmalloc(len+3);
+ strcpy(end, name);
+ strcat(end,"$e");
+
+ lang_add_assignment
+ ( exp_assop('=',name, exp_nameop(NAME,".")));
+
+ lang_add_data
+ (LONG, exp_binop('-',
+ exp_binop ( '/',
+ exp_binop ( '-',
+ exp_nameop(NAME, end),
+ exp_nameop(NAME,".")),
+ exp_intop(4)),
+
+ exp_intop(2)));
+
+
+ lang_add_wild(name, (char *)NULL);
+ lang_add_data(LONG, exp_intop(0));
+ lang_add_assignment
+ (exp_assop('=', end, exp_nameop(NAME,".")));
+p = p->next;
+ }
+
+
+
+ stat_ptr = old;
+}
void
DEFUN_VOID(lang_process)
{
common_section.userdata = (PTR)&common_section_userdata;
+
/* Run through the contours of the script and attatch input sections
to the correct output sections
*/
+ find_constructors();
map_input_to_output_sections(statement_list.head, (char *)NULL,
( lang_output_section_statement_type *)NULL);
+
/* Find any sections not attatched explicitly and handle them */
lang_place_orphans();
current_section->fill = fill;
current_section->region = lang_memory_region_lookup(memspec);
stat_ptr = &statement_list;
+
+ /* We remember if we are closing a .data section, since we use it to
+ store constructors in */
+ if (strcmp(current_section->name, ".data") ==0) {
+ end_of_data_section_statement_list = statement_list;
+
+ }
}
/*
Create an absolute symbol with the given name with the value of the
int unix_relocate;
+#ifdef GNU960
+/* Indicates whether output file will be b.out (default) or coff */
+enum target_flavour_enum output_flavor = BFD_BOUT_FORMAT;
+#endif
output_filename = "a.out";
#ifdef GNU960
- check_v960( argc, argv );
+ {
+ int i;
+
+ check_v960( argc, argv );
+ emulation = GLD960_EMULATION_NAME;
+ for ( i = 1; i < argc; i++ ){
+ if ( !strcmp(argv[i],"-Fcoff") ){
+ emulation = LNK960_EMULATION_NAME;
+ output_flavor = BFD_COFF_FORMAT;
+ break;
+ }
+ }
+ }
+#else
+ emulation = (char *) getenv(EMULATION_ENVIRON);
#endif
- emulation = (char *) getenv(EMULATION_ENVIRON);
-
/* Initialize the data about options. */
trace_files = false;
config.magic_demand_paged = true ;
config.make_executable = true;
-
-#ifdef GNU960
- ldemul_choose_mode(LNK960_EMULATION_NAME);
-#else
if (emulation == (char *)NULL) {
emulation= DEFAULT_EMULATION;
}
ldemul_choose_mode(emulation);
-#endif
+
default_target = ldemul_choose_target();
struct lang_input_statement_struct *entry;
{
if (entry->asymbols == (asymbol **)NULL) {
- size_t table_size = get_symtab_upper_bound(desc);
+ bfd_size_type table_size = get_symtab_upper_bound(desc);
entry->asymbols = (asymbol **)ldmalloc(table_size);
entry->symbol_count = bfd_canonicalize_symtab(desc, entry->asymbols) ;
ASSERT(sym->udata == 0);
- /* Just place onto correct chain */
- if (flag_is_common(this_symbol_flags)) {
- /* If we have a definition of this symbol already then
- * this common turns into a reference. Also we only
- * ever point to the largest common, so if we
- * have a common, but it's bigger that the new symbol
- * the turn this into a reference too.
- */
- if (sp->sdefs_chain)
- {
- /* This is a common symbol, but we already have a definition
- for it, so just link it into the ref chain as if
- it were a reference
- */
- refize(sp, nlist_p);
- }
- else if (sp->scoms_chain) {
- /* If we have a previous common, keep only the biggest */
- if ( (*(sp->scoms_chain))->value > sym->value) {
- /* other common is bigger, throw this one away */
- refize(sp, nlist_p);
+ if (flag_is_constructor(this_symbol_flags)) {
+ /* Just remeber the name, do it once per name by placing it as if
+ it were a zero sized common. The next ref */
+ ldlang_add_constructor(sp);
+
+ }
+ else {
+ if (flag_is_common(this_symbol_flags)) {
+ /* If we have a definition of this symbol already then
+ * this common turns into a reference. Also we only
+ * ever point to the largest common, so if we
+ * have a common, but it's bigger that the new symbol
+ * the turn this into a reference too.
+ */
+ if (sp->sdefs_chain)
+ {
+ /* This is a common symbol, but we already have a definition
+ for it, so just link it into the ref chain as if
+ it were a reference
+ */
+ refize(sp, nlist_p);
+ }
+ else if (sp->scoms_chain) {
+ /* If we have a previous common, keep only the biggest */
+ if ( (*(sp->scoms_chain))->value > sym->value) {
+ /* other common is bigger, throw this one away */
+ refize(sp, nlist_p);
+ }
+ else if (sp->scoms_chain != nlist_p) {
+ /* other common is smaller, throw that away */
+ refize(sp, sp->scoms_chain);
+ sp->scoms_chain = nlist_p;
+ }
}
- else if (sp->scoms_chain != nlist_p) {
- /* other common is smaller, throw that away */
- refize(sp, sp->scoms_chain);
+ else {
+ /* This is the first time we've seen a common, so
+ * remember it - if it was undefined before, we know it's defined now
+ */
+ if (sp->srefs_chain)
+ undefined_global_sym_count--;
+
+ commons_pending++;
sp->scoms_chain = nlist_p;
}
}
- else {
- /* This is the first time we've seen a common, so
- * remember it - if it was undefined before, we know it's defined now
- */
- if (sp->srefs_chain)
- undefined_global_sym_count--;
- commons_pending++;
- sp->scoms_chain = nlist_p;
- }
- }
-
- else if (flag_is_defined(this_symbol_flags)) {
- /* This is the definition of a symbol, add to def chain */
- if (sp->sdefs_chain && (*(sp->sdefs_chain))->section != sym->section) {
- /* Multiple definition */
- asymbol *sy = *(sp->sdefs_chain);
- lang_input_statement_type *stat = (lang_input_statement_type *) sy->the_bfd->usrdata;
- lang_input_statement_type *stat1 = (lang_input_statement_type *) sym->the_bfd->usrdata;
- asymbol ** stat1_symbols = stat1 ? stat1->asymbols: 0;
- asymbol ** stat_symbols = stat ? stat->asymbols:0;
+ else if (flag_is_defined(this_symbol_flags)) {
+ /* This is the definition of a symbol, add to def chain */
+ if (sp->sdefs_chain && (*(sp->sdefs_chain))->section != sym->section) {
+ /* Multiple definition */
+ asymbol *sy = *(sp->sdefs_chain);
+ lang_input_statement_type *stat = (lang_input_statement_type *) sy->the_bfd->usrdata;
+ lang_input_statement_type *stat1 = (lang_input_statement_type *) sym->the_bfd->usrdata;
+ asymbol ** stat1_symbols = stat1 ? stat1->asymbols: 0;
+ asymbol ** stat_symbols = stat ? stat->asymbols:0;
- multiple_def_count++;
- info("%C: multiple definition of `%T'\n",
- sym->the_bfd,
- sym->section,
- stat1_symbols,
- sym->value,
- sym);
+ multiple_def_count++;
+ info("%C: multiple definition of `%T'\n",
+ sym->the_bfd,
+ sym->section,
+ stat1_symbols,
+ sym->value,
+ sym);
- info("%C: first seen here\n",
- sy->the_bfd,
- sy->section,
- stat_symbols,
- sy->value);
+ info("%C: first seen here\n",
+ sy->the_bfd,
+ sy->section,
+ stat_symbols,
+ sy->value);
+ }
+ else {
+ sym->udata =(PTR)( sp->sdefs_chain);
+ sp->sdefs_chain = nlist_p;
+ }
+ /* A definition overrides a common symbol */
+ if (sp->scoms_chain) {
+ refize(sp, sp->scoms_chain);
+ sp->scoms_chain = 0;
+ commons_pending--;
+ }
+ else if (sp->srefs_chain) {
+ /* If previously was undefined, then remember as defined */
+ undefined_global_sym_count--;
+ }
}
else {
- sym->udata =(PTR)( sp->sdefs_chain);
- sp->sdefs_chain = nlist_p;
- }
- /* A definition overrides a common symbol */
- if (sp->scoms_chain) {
- refize(sp, sp->scoms_chain);
- sp->scoms_chain = 0;
- commons_pending--;
- }
- else if (sp->srefs_chain) {
- /* If previously was undefined, then remember as defined */
- undefined_global_sym_count--;
- }
- }
- else {
- if (sp->scoms_chain == (asymbol **)NULL
- && sp->srefs_chain == (asymbol **)NULL
- && sp->sdefs_chain == (asymbol **)NULL) {
- /* And it's the first time we've seen it */
- undefined_global_sym_count++;
+ if (sp->scoms_chain == (asymbol **)NULL
+ && sp->srefs_chain == (asymbol **)NULL
+ && sp->sdefs_chain == (asymbol **)NULL) {
+ /* And it's the first time we've seen it */
+ undefined_global_sym_count++;
- }
+ }
- refize(sp, nlist_p);
+ refize(sp, nlist_p);
+ }
}
ASSERT(sp->sdefs_chain == 0 || sp->scoms_chain == 0);
{
asymbol *p = *q;
- if (flag_is_undefined_or_global_or_common(p->flags))
+ if (flag_is_undefined_or_global_or_common_or_constructor(p->flags))
{
Q_enter_global_ref(q);
}
+ if (p->flags & BSF_INDIRECT) {
+ add_indirect(q);
+ }
+
+ if (p->flags & BSF_WARNING) {
+ add_warning(p);
+ }
ASSERT(p->flags != 0);
}
}
{
boolean retval;
- if ((bfd_check_format(abfd,format) == true) && BFD_COFF_FILE_P(abfd)) {
- return true;
+ if ((bfd_check_format(abfd,format) == true)
+ && (abfd->xvec->flavour == output_flavor) ){
+ return true;
}
+
+
return false;
}
#endif
bfd *subfile_offset;
{
register struct lang_input_statement_struct *subentry;
- subentry = (struct lang_input_statement_struct *) ldmalloc (sizeof (struct lang_input_statement_struct));
+ subentry = (struct lang_input_statement_struct *) ldmalloc ((bfd_size_type)(sizeof (struct lang_input_statement_struct)));
subentry->filename = subfile_offset -> filename;
subentry->local_sym_name = subfile_offset->filename;
subentry->asymbols = 0;