old-cross-binutils/gas/config/obj-aout.c

550 lines
14 KiB
C
Raw Normal View History

1991-04-04 18:19:53 +00:00
/* a.out object file format
Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 2,
or (at your option) any later version.
GAS 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 GAS; see the file COPYING. If not, write
to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
1991-04-04 18:19:53 +00:00
#include "as.h"
#ifdef BFD_ASSEMBLER
#undef NO_RELOC
#include "aout/aout64.h"
#endif
1991-04-04 18:19:53 +00:00
#include "obstack.h"
#ifndef BFD_ASSEMBLER
/* in: segT out: N_TYPE bits */
const short seg_N_TYPE[] =
{
N_ABS,
N_TEXT,
N_DATA,
N_BSS,
N_UNDF, /* unknown */
N_UNDF, /* error */
* Extensive changes to permit symbols to contain any expression type and to delay the computation of the expression until the value is actually needed. This permits setting symbols to values calculated based on object code size. Expressions were changed to no longer be in a section, to stop the overloading of segment and expression type that previously occurred. * as.c (big_section, pass1_section, diff_section, absent_section): Removed. (expr_section): Added (used for dummy symbols which hold intermediate expression values). (perform_an_assembly_pass): Create expr_section, do not create the sections now removed. * as.h (segT): Removed SEG_ABSENT, SEG_PASS1, SEG_BIG, and SEG_DIFFERENCE. Added SEG_EXPR. (SEG_NORMAL): Corresponding changes. * subsegs.c (seg_name, subsegs_begin): Changed accordingly. * write.c (write_object_file): Ditto. * config/obj-aout.c (seg_N_TYPE): Ditto. * config/obj-bout.c (seg_N_TYPE): Ditto. * config/obj-coff.c (seg_N_TYPE): Ditto. * config/obj-coffbfd.c (seg_N_TYPE): Ditto. * config/obj-vms.c (seg_N_TYPE): Ditto. * expr.h (operatorT): Moved in from expr.c, added some values. (expressionS): Added X_op field, removed X_seg field; renamed X_subtract_symbol to X_op_symbol. * expr.c: Extensive changes to assign expression types rather than sections and to simplify the parsing. * write.c (fix_new_internal): New static function. (fix_new): Removed sub_symbol argument. (fix_new_exp): New function, takes expression argument. * write.h: Prototype changes for fix_new and fix_new_exp. * cond.c (s_if): Changed accordingly. * read.c (s_lsym, pseudo_set, emit_expr, parse_bitfield_cons, parse_repeat_cons, get_segmented_expression, get_known_segmented_expression, get_absolute_expression): Ditto. * symbols.c (resolve_symbol_value, S_GET_VALUE, S_SET_VALUE): Ditto. * write.c (write_object_file): Ditto. * config/obj-coff.c (obj_coff_def, obj_coff_val): Ditto. * config/obj-coffbfd.c (obj_coff_def, obj_coff_val, obj_coff_endef, yank_symbols): Ditto. * config/obj-elf.c (obj_elf_stab_generic, obj_elf_size): Ditto. * config/tc-a29k.c (md_assemble, parse_operand, machine_ip, print_insn, md_operand): Ditto. * config/tc-h8300.c (parse_exp, colonmod24, check_operand, do_a_fix_imm, build_bytes): Ditto. * config/tc-h8500.c (parse_exp, skip_colonthing, parse_reglist, get_specific, check, insert, md_convert_frag): Ditto. * config/tc-hppa.c (the_insn, fix_new_hppa, cons_fix_new_hppa, md_assemble, pa_ip, getExpression, getAbsoluteExpression, evaluateAbsolute, pa_build_unwind_subspace, pa_entry, process_exit): Ditto. * config/tc-hppa.h (STAB_FIXUP, is_DP_relative, is_PC_relative, is_complex): Ditto. * config/tc-i386.c (pe, md_assemble, i386_operand, md_estimate_size_before_relax, md_create_long_jump): Ditto. * config/tc-i860.c (md_assemble, getExpression, print_insn): Ditto. * config/tc-i960.c (parse_expr, subs, segs, md_convert_frag, get_cdisp, mem_fmt, parse_ldconst, relax_cobr, s_sysproc, i960_handle_align): Ditto. * config/tc-m68k.c (struct m68k_exp, struct m68k_it, seg, op, subs, add_fix, isvar, m68k_ip, md_assemble, md_convert_frag_1, md_estimate_size_before_relax, md_create_long_jump, get_num): Ditto. * config/tc-m88k.c (md_assemble, get_imm16, get_pcr, md_create_short_jump, md_create_long_jump): Ditto. * config/tc-mips.c (md_assemble, append_insn, gp_reference, macro_build, macro, my_getExpression): Ditto. Also removed get_optional_absolute_expression; just use get_absolute_expression instead. * config/tc-ns32k.c (get_addr_mode, evaluate_expr, convert_iif, fix_new_ns32k, fix_new_ns32k_exp, cons_fix_new_ns32k): Ditto. * config/tc-ns32k.h (fix_new_ns32k prototype): Ditto. * config/tc-sh.c (parse_exp, check, insert, md_convert_frag): Ditto. * config/tc-sparc.c (md_assemble, sparc_ip, getExpression, print_insn): Ditto. * config/tc-tahoe.c (struct top, md_estimate_size_before_relax, tip_op, md_assemble): Ditto. * config/tc-vax.c (seg_of_operand, md_assemble, md_estimate_size_before_relax, md_create_long_jump): Ditto. * config/tc-z8k.c (parse_exp, check_operand, newfix): Ditto.
1993-07-21 00:41:42 +00:00
N_UNDF, /* expression */
N_UNDF, /* debug */
N_UNDF, /* ntv */
N_UNDF, /* ptv */
N_REGISTER, /* register */
1991-04-04 18:19:53 +00:00
};
const segT N_TYPE_seg[N_TYPE + 2] =
{ /* N_TYPE == 0x1E = 32-2 */
SEG_UNKNOWN, /* N_UNDF == 0 */
SEG_GOOF,
SEG_ABSOLUTE, /* N_ABS == 2 */
SEG_GOOF,
SEG_TEXT, /* N_TEXT == 4 */
SEG_GOOF,
SEG_DATA, /* N_DATA == 6 */
SEG_GOOF,
SEG_BSS, /* N_BSS == 8 */
SEG_GOOF,
SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */
SEG_GOOF,
1991-04-04 18:19:53 +00:00
};
#endif
static void obj_aout_line PARAMS ((int));
static void obj_aout_weak PARAMS ((int));
1991-04-04 18:19:53 +00:00
const pseudo_typeS obj_pseudo_table[] =
{
{"line", obj_aout_line, 0}, /* source code line number */
{"ln", obj_aout_line, 0}, /* coff line number that we use anyway */
1991-04-04 18:19:53 +00:00
{"weak", obj_aout_weak, 0}, /* mark symbol as weak. */
/* coff debug pseudos (ignored) */
{"def", s_ignore, 0},
{"dim", s_ignore, 0},
{"endef", s_ignore, 0},
{"ident", s_ignore, 0},
{"line", s_ignore, 0},
{"ln", s_ignore, 0},
{"scl", s_ignore, 0},
{"size", s_ignore, 0},
{"tag", s_ignore, 0},
{"type", s_ignore, 0},
{"val", s_ignore, 0},
{"version", s_ignore, 0},
{"optim", s_ignore, 0}, /* For sun386i cc (?) */
/* other stuff */
{"ABORT", s_abort, 0},
{NULL} /* end sentinel */
}; /* obj_pseudo_table */
#ifdef BFD_ASSEMBLER
void
obj_aout_frob_symbol (sym, punt)
symbolS *sym;
int *punt;
{
flagword flags;
asection *sec;
int desc, type, other;
flags = sym->bsym->flags;
desc = S_GET_DESC (sym);
type = S_GET_TYPE (sym);
other = S_GET_OTHER (sym);
sec = sym->bsym->section;
/* Only frob simple symbols this way right now. */
if (! (type & ~ (N_TYPE | N_EXT)))
{
if (type == (N_UNDF | N_EXT)
&& sec == &bfd_abs_section)
sym->bsym->section = sec = bfd_und_section_ptr;
if ((type & N_TYPE) != N_INDR
&& (type & N_TYPE) != N_SETA
&& (type & N_TYPE) != N_SETT
&& (type & N_TYPE) != N_SETD
&& (type & N_TYPE) != N_SETB
&& type != N_WARNING
&& (sec == &bfd_abs_section
|| sec == &bfd_und_section))
return;
if (flags & BSF_EXPORT)
type |= N_EXT;
switch (type & N_TYPE)
{
case N_SETA:
case N_SETT:
case N_SETD:
case N_SETB:
/* Set the debugging flag for constructor symbols so that
BFD leaves them alone. */
sym->bsym->flags |= BSF_DEBUGGING;
/* You can't put a common symbol in a set. The way a set
element works is that the symbol has a definition and a
name, and the linker adds the definition to the set of
that name. That does not work for a common symbol,
because the linker can't tell which common symbol the
user means. FIXME: Using as_bad here may be
inappropriate, since the user may want to force a
particular type without regard to the semantics of sets;
on the other hand, we certainly don't want anybody to be
mislead into thinking that their code will work. */
if (S_IS_COMMON (sym))
as_bad ("Attempt to put a common symbol into set %s",
S_GET_NAME (sym));
/* Similarly, you can't put an undefined symbol in a set. */
else if (! S_IS_DEFINED (sym))
as_bad ("Attempt to put an undefined symbol into set %s",
S_GET_NAME (sym));
break;
case N_INDR:
/* Put indirect symbols in the indirect section. */
sym->bsym->section = bfd_ind_section_ptr;
sym->bsym->flags |= BSF_INDIRECT;
if (type & N_EXT)
{
sym->bsym->flags |= BSF_EXPORT;
sym->bsym->flags &=~ BSF_LOCAL;
}
break;
case N_WARNING:
/* Mark warning symbols. */
sym->bsym->flags |= BSF_WARNING;
break;
}
}
else
{
sym->bsym->flags |= BSF_DEBUGGING;
}
S_SET_TYPE (sym, type);
/* Double check weak symbols. */
if (sym->bsym->flags & BSF_WEAK)
{
if (S_IS_COMMON (sym))
as_bad ("Symbol `%s' can not be both weak and common",
S_GET_NAME (sym));
}
}
void
obj_aout_frob_file ()
{
/* Relocation processing may require knowing the VMAs of the sections.
Since writing to a section will cause the BFD back end to compute the
VMAs, fake it out here.... */
bfd_byte b = 0;
boolean x = true;
if (bfd_section_size (stdoutput, text_section) != 0)
{
x = bfd_set_section_contents (stdoutput, text_section, &b, (file_ptr) 0,
(bfd_size_type) 1);
}
else if (bfd_section_size (stdoutput, data_section) != 0)
{
x = bfd_set_section_contents (stdoutput, data_section, &b, (file_ptr) 0,
(bfd_size_type) 1);
}
assert (x == true);
}
#else
1991-04-04 18:19:53 +00:00
/* Relocation. */
/*
* emit_relocations()
*
* Crawl along a fixS chain. Emit the segment's relocations.
*/
void
obj_emit_relocations (where, fixP, segment_address_in_file)
char **where;
fixS *fixP; /* Fixup chain for this segment. */
relax_addressT segment_address_in_file;
1991-04-04 18:19:53 +00:00
{
for (; fixP; fixP = fixP->fx_next)
if (fixP->fx_done == 0)
{
tc_aout_fix_to_chars (*where, fixP, segment_address_in_file);
*where += md_reloc_size;
}
}
1991-04-04 18:19:53 +00:00
#ifndef obj_header_append
1991-04-04 18:19:53 +00:00
/* Aout file generation & utilities */
void
obj_header_append (where, headers)
char **where;
object_headers *headers;
1991-04-04 18:19:53 +00:00
{
tc_headers_hook (headers);
#ifdef CROSS_COMPILE
md_number_to_chars (*where, headers->header.a_info, sizeof (headers->header.a_info));
*where += sizeof (headers->header.a_info);
md_number_to_chars (*where, headers->header.a_text, sizeof (headers->header.a_text));
*where += sizeof (headers->header.a_text);
md_number_to_chars (*where, headers->header.a_data, sizeof (headers->header.a_data));
*where += sizeof (headers->header.a_data);
md_number_to_chars (*where, headers->header.a_bss, sizeof (headers->header.a_bss));
*where += sizeof (headers->header.a_bss);
md_number_to_chars (*where, headers->header.a_syms, sizeof (headers->header.a_syms));
*where += sizeof (headers->header.a_syms);
md_number_to_chars (*where, headers->header.a_entry, sizeof (headers->header.a_entry));
*where += sizeof (headers->header.a_entry);
md_number_to_chars (*where, headers->header.a_trsize, sizeof (headers->header.a_trsize));
*where += sizeof (headers->header.a_trsize);
md_number_to_chars (*where, headers->header.a_drsize, sizeof (headers->header.a_drsize));
*where += sizeof (headers->header.a_drsize);
#else /* CROSS_COMPILE */
append (where, (char *) &headers->header, sizeof (headers->header));
#endif /* CROSS_COMPILE */
1991-04-04 18:19:53 +00:00
}
#endif
void
obj_symbol_to_chars (where, symbolP)
char **where;
symbolS *symbolP;
1991-04-04 18:19:53 +00:00
{
md_number_to_chars ((char *) &(S_GET_OFFSET (symbolP)), S_GET_OFFSET (symbolP), sizeof (S_GET_OFFSET (symbolP)));
md_number_to_chars ((char *) &(S_GET_DESC (symbolP)), S_GET_DESC (symbolP), sizeof (S_GET_DESC (symbolP)));
md_number_to_chars ((char *) &(symbolP->sy_symbol.n_value), S_GET_VALUE (symbolP), sizeof (symbolP->sy_symbol.n_value));
append (where, (char *) &symbolP->sy_symbol, sizeof (obj_symbol_type));
}
1991-04-04 18:19:53 +00:00
void
obj_emit_symbols (where, symbol_rootP)
char **where;
symbolS *symbol_rootP;
1991-04-04 18:19:53 +00:00
{
symbolS *symbolP;
/* Emit all symbols left in the symbol chain. */
for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
{
/* Used to save the offset of the name. It is used to point
to the string in memory but must be a file offset. */
register char *temp;
temp = S_GET_NAME (symbolP);
S_SET_OFFSET (symbolP, symbolP->sy_name_offset);
1991-04-04 18:19:53 +00:00
/* Any symbol still undefined and is not a dbg symbol is made N_EXT. */
if (!S_IS_DEBUG (symbolP) && !S_IS_DEFINED (symbolP))
S_SET_EXTERNAL (symbolP);
/* Adjust the type of a weak symbol. */
if (S_GET_WEAK (symbolP))
{
switch (S_GET_TYPE (symbolP))
{
case N_UNDF: S_SET_TYPE (symbolP, N_WEAKU); break;
case N_ABS: S_SET_TYPE (symbolP, N_WEAKA); break;
case N_TEXT: S_SET_TYPE (symbolP, N_WEAKT); break;
case N_DATA: S_SET_TYPE (symbolP, N_WEAKD); break;
case N_BSS: S_SET_TYPE (symbolP, N_WEAKB); break;
default: as_bad ("%s: bad type for weak symbol", temp); break;
}
}
obj_symbol_to_chars (where, symbolP);
S_SET_NAME (symbolP, temp);
}
}
#endif /* ! BFD_ASSEMBLER */
static void
obj_aout_line (ignore)
int ignore;
{
/* Assume delimiter is part of expression.
BSD4.2 as fails with delightful bug, so we
are not being incompatible here. */
new_logical_line ((char *) NULL, (int) (get_absolute_expression ()));
demand_empty_rest_of_line ();
} /* obj_aout_line() */
1991-04-04 18:19:53 +00:00
/* Handle .weak. This is a GNU extension. */
static void
obj_aout_weak (ignore)
int ignore;
{
char *name;
int c;
symbolS *symbolP;
do
{
name = input_line_pointer;
c = get_symbol_end ();
symbolP = symbol_find_or_make (name);
*input_line_pointer = c;
SKIP_WHITESPACE ();
S_SET_WEAK (symbolP);
if (c == ',')
{
input_line_pointer++;
SKIP_WHITESPACE ();
if (*input_line_pointer == '\n')
c = '\n';
}
}
while (c == ',');
demand_empty_rest_of_line ();
}
void
obj_read_begin_hook ()
{
}
#ifndef BFD_ASSEMBLER
1991-04-04 18:19:53 +00:00
void
obj_crawl_symbol_chain (headers)
object_headers *headers;
1991-04-04 18:19:53 +00:00
{
symbolS *symbolP;
symbolS **symbolPP;
int symbol_number = 0;
tc_crawl_symbol_chain (headers);
symbolPP = &symbol_rootP; /*->last symbol chain link. */
while ((symbolP = *symbolPP) != NULL)
{
if (flag_readonly_data_in_text && (S_GET_SEGMENT (symbolP) == SEG_DATA))
{
S_SET_SEGMENT (symbolP, SEG_TEXT);
} /* if pusing data into text */
* Removed sy_forward and replaced it with an undefined expression as the value of a symbol. * struc-symbol.h (struct symbol): Removed sy_forward field. Added sy_resolved and sy_resolving single bit fields. * symbols.c (symbol_new): Don't initialize sy_forward field. (resolve_symbol_value): New function to adjust symbol value by fragment address, using recursion to resolve forward symbols. * symbols.h: Added prototype for new function. * read.c (pseudo_set): Set symbolP->sy_value to an undefined expression rather than setting symbolP->sy_forward. * write.c (write_object_file): Use resolve_symbol_value on symbols, keeping the common case (the old behaviour) inline. * config/obj-aout.c (obj_aout_frob_symbol): Removed sy_forward handling (subsumed by write.c change). * config/obj-coff.c, config/obj-coffbfd.c (obj_coff_val): Set sy_value rather than sy_forward. * config/obj-coffbfd.c (obj_coff_endef, yank_symbols): Check expression segment rather than sy_forward. (yank_symbols): Use resolve_symbol_value. (crawl_symbols): Removed extra pass over symbols. * config/obj-aout.c, config/obj-bout.c, config/obj-coff.c, config/obj-vms.c (obj_crawl_symbol_chain): Removed extra pass over symbols which handled sy_forward; use resolve_symbol_value instead. * config/obj-coff.h, config/obj-coffbfd.h (obj_frob_forward_symbol): Define. * config/obj-elf.c (obj_elf_stab_generic): Check expression segment rather than sy_forward. * config/obj-vms.c (VMS_Check_For_Main): Don't initialize sy_forward; do initialize sy_resolved and sy_resolving. * config/tc-hppa.h (STAB_FIXUP): Use sy_value, not sy_forward.
1993-07-14 22:21:25 +00:00
resolve_symbol_value (symbolP);
/* OK, here is how we decide which symbols go out into the brave
new symtab. Symbols that do are:
* symbols with no name (stabd's?)
* symbols with debug info in their N_TYPE
Symbols that don't are:
* symbols that are registers
* symbols with \1 as their 3rd character (numeric labels)
* "local labels" as defined by S_LOCAL_NAME(name) if the -L
switch was passed to gas.
All other symbols are output. We complain if a deleted
symbol was marked external. */
if (!S_IS_REGISTER (symbolP)
&& (!S_GET_NAME (symbolP)
|| S_IS_DEBUG (symbolP)
|| !S_IS_DEFINED (symbolP)
|| S_IS_EXTERNAL (symbolP)
|| (S_GET_NAME (symbolP)[0] != '\001'
&& (flag_keep_locals || !S_LOCAL_NAME (symbolP)))))
{
symbolP->sy_number = symbol_number++;
/* The + 1 after strlen account for the \0 at the
1991-04-04 18:19:53 +00:00
end of each string */
if (!S_IS_STABD (symbolP))
{
/* Ordinary case. */
symbolP->sy_name_offset = string_byte_count;
string_byte_count += strlen (S_GET_NAME (symbolP)) + 1;
}
else /* .Stabd case. */
symbolP->sy_name_offset = 0;
symbolPP = &(symbol_next (symbolP));
}
else
{
if (S_IS_EXTERNAL (symbolP) || !S_IS_DEFINED (symbolP))
/* This warning should never get triggered any more.
Well, maybe if you're doing twisted things with
register names... */
{
as_bad ("Local symbol %s never defined.", decode_local_label_name (S_GET_NAME (symbolP)));
} /* oops. */
/* Unhook it from the chain */
*symbolPP = symbol_next (symbolP);
} /* if this symbol should be in the output */
} /* for each symbol */
H_SET_SYMBOL_TABLE_SIZE (headers, symbol_number);
}
1991-04-04 18:19:53 +00:00
/*
* Find strings by crawling along symbol table chain.
*/
void
obj_emit_strings (where)
char **where;
1991-04-04 18:19:53 +00:00
{
symbolS *symbolP;
#ifdef CROSS_COMPILE
/* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */
md_number_to_chars (*where, string_byte_count, sizeof (string_byte_count));
*where += sizeof (string_byte_count);
#else /* CROSS_COMPILE */
append (where, (char *) &string_byte_count, (unsigned long) sizeof (string_byte_count));
#endif /* CROSS_COMPILE */
1991-04-04 18:19:53 +00:00
for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
{
if (S_GET_NAME (symbolP))
append (&next_object_file_charP, S_GET_NAME (symbolP),
(unsigned long) (strlen (S_GET_NAME (symbolP)) + 1));
} /* walk symbol chain */
}
#ifndef AOUT_VERSION
#define AOUT_VERSION 0
#endif
void
obj_pre_write_hook (headers)
object_headers *headers;
{
H_SET_DYNAMIC (headers, 0);
H_SET_VERSION (headers, AOUT_VERSION);
H_SET_MACHTYPE (headers, AOUT_MACHTYPE);
tc_aout_pre_write_hook (headers);
}
void
DEFUN_VOID (s_sect)
{
/* Strip out the section name */
char *section_name;
char *section_name_end;
char c;
unsigned int len;
unsigned int exp;
char *save;
section_name = input_line_pointer;
c = get_symbol_end ();
section_name_end = input_line_pointer;
len = section_name_end - section_name;
input_line_pointer++;
save = input_line_pointer;
SKIP_WHITESPACE ();
if (c == ',')
{
exp = get_absolute_expression ();
}
else if (*input_line_pointer == ',')
{
input_line_pointer++;
exp = get_absolute_expression ();
}
else
{
input_line_pointer = save;
exp = 0;
}
if (exp >= 1000)
{
as_bad ("subsegment index too high");
}
if (strcmp (section_name, ".text") == 0)
{
subseg_set (SEG_TEXT, (subsegT) exp);
}
if (strcmp (section_name, ".data") == 0)
{
if (flag_readonly_data_in_text)
subseg_set (SEG_TEXT, (subsegT) exp + 1000);
else
subseg_set (SEG_DATA, (subsegT) exp);
}
*section_name_end = c;
}
#endif /* ! BFD_ASSEMBLER */
1991-04-04 18:19:53 +00:00
/* end of obj-aout.c */