binutils-gdb/gas/config/obj-elf.c
Ian Lance Taylor 4f0bccc7d8 Some more gcc lint, and:
* read.c (change_to_section): Removed.  This is now done by
	subseg_new.
	(get_stab_string_offset): Rearranged somewhat.  Create the section
	using subseg_new.  Store the string index in seg_info, rather than
	in a static variable.  Force the first string to be empty.  Use
	frag_more rather than FRAG_APPEND_1_CHAR.
	(s_stab_generic): Rewrote.
	* subsegs.h (segment_info_type): Added stabu union.
	* subsegs.c (subseg_new): Initialize stab_string_size to 0.
	* config/obj-aout.c: Don't include aout/stab_gnu.h.
	(obj_aout_stab, obj_aout_desc): Removed.
	(obj_pseudo_table): Removed desc and stabX entries.
	* config/obj-bout.c: Same changes as config/obj-aout.c.
	* config/obj-bout.h (S_SET_TYPE): Define.
	(tc_bout_fix_to_chars): Declare.
	* config/obj-coff.c (obj_coff_stab): Removed.
	(obj_pseudo_table): Removed desc and stabX entries.
	* config/obj-coff.h (SEPARATE_STAB_SECTIONS): Define.
	* config/obj-coffbfd.c (current_stab_symbol): Removed.
	* config/obj-coffbfd.h (obj_symbol_type): Removed n_strx, n_type,
	n_other, n_desc and n_value fields.
	(S_{S,G}ET_{OFFSET,OTHER,TYPE,DESC}): Removed.
	(MAKE_STAB_SYMBOL): Removed.
	* config/obj-ecoff.c (obj_ecoff_stab): Renamed to ecoff_stab.
	Changed arguments and removed parsing code.
	(obj_pseudo_table): Removed stabX entries.
	* config/obj-ecoff.h (ecoff_stab): Declare.
	(OBJ_PROCESS_STAB): Define.
	* config/obj-elf.c: Don't include aout/stab_gnu.h.
	(obj_elf_stab, obj_elf_xstab, obj_elf_desc,
	elf_stab_symbol_string, elf_stab_symbol, obj_elf_stab_generic):
	Removed.
	(obj_pseudo_table): Removed desc, stabX and xstabs entries.
	(obj_elf_version): Use subseg_new, not bfd_make_section.  Don't
	set SEC_LOAD for .note section.
	(adjust_stab_sections): Get frag pointer from seg_info, rather
	than looking through frags.
	* config/obj-elf.h (S_{S,G}ET_{OTHER,TYPE,DESC}): Removed.
	(SEPARATE_STAB_SECTIONS, INIT_STAB_SECTION, OBJ_PROCESS_STAB):
	Define.
	* config/obj-vms.c (obj_aout_stab): Removed.
	(obj_pseudo_table): Removed stabX entries.
	* config/obj-vms.h (S_SET_TYPE): Define.
1993-09-14 17:58:35 +00:00

748 lines
17 KiB
C

/* ELF object file format
Copyright (C) 1992, 1993 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. */
#include "as.h"
#include "subsegs.h"
#include "obstack.h"
static int obj_elf_write_symbol_p PARAMS ((symbolS *sym));
static void obj_elf_line PARAMS ((int));
void obj_elf_version PARAMS ((int));
static void obj_elf_size PARAMS ((int));
static void obj_elf_type PARAMS ((int));
static void obj_elf_ident PARAMS ((int));
static void obj_elf_weak PARAMS ((int));
static void obj_elf_local PARAMS ((int));
static void obj_elf_common PARAMS ((int));
const pseudo_typeS obj_pseudo_table[] =
{
{"comm", obj_elf_common, 0},
{"ident", obj_elf_ident, 0},
{"local", obj_elf_local, 0},
{"previous", obj_elf_previous, 0},
{"section", obj_elf_section, 0},
{"size", obj_elf_size, 0},
{"type", obj_elf_type, 0},
{"version", obj_elf_version, 0},
{"weak", obj_elf_weak, 0},
/* These are used for stabs-in-elf configurations. */
{"line", obj_elf_line, 0},
/* These are used for dwarf. */
{"2byte", cons, 2},
{"4byte", cons, 4},
{"8byte", cons, 8},
{NULL} /* end sentinel */
};
#undef NO_RELOC
#include "aout/aout64.h"
void
elf_file_symbol (s)
char *s;
{
symbolS *sym;
sym = symbol_new (s, absolute_section, (valueT) 0, (struct frag *) 0);
sym->sy_frag = &zero_address_frag;
sym->bsym->flags |= BSF_FILE;
if (symbol_rootP != sym)
{
symbol_remove (sym, &symbol_rootP, &symbol_lastP);
symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP);
#ifdef DEBUG
verify_symbol_chain (symbol_rootP, symbol_lastP);
#endif
}
}
static void
obj_elf_common (ignore)
int ignore;
{
char *name;
char c;
char *p;
int temp, size;
symbolS *symbolP;
name = input_line_pointer;
c = get_symbol_end ();
/* just after name is now '\0' */
p = input_line_pointer;
*p = c;
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
as_bad ("Expected comma after symbol-name");
ignore_rest_of_line ();
return;
}
input_line_pointer++; /* skip ',' */
if ((temp = get_absolute_expression ()) < 0)
{
as_bad (".COMMon length (%d.) <0! Ignored.", temp);
ignore_rest_of_line ();
return;
}
size = temp;
*p = 0;
symbolP = symbol_find_or_make (name);
*p = c;
if (S_IS_DEFINED (symbolP))
{
as_bad ("Ignoring attempt to re-define symbol");
ignore_rest_of_line ();
return;
}
if (S_GET_VALUE (symbolP) != 0)
{
if (S_GET_VALUE (symbolP) != size)
{
as_warn ("Length of .comm \"%s\" is already %ld. Not changed to %d.",
S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size);
}
}
know (symbolP->sy_frag == &zero_address_frag);
if (*input_line_pointer != ',')
{
as_bad ("Expected comma after common length");
ignore_rest_of_line ();
return;
}
input_line_pointer++;
SKIP_WHITESPACE ();
if (*input_line_pointer != '"')
{
temp = get_absolute_expression ();
if (temp < 0)
{
temp = 0;
as_warn ("Common alignment negative; 0 assumed");
}
if (symbolP->local)
{
segT old_sec;
int old_subsec;
char *pfrag;
int align;
/* allocate_bss: */
old_sec = now_seg;
old_subsec = now_subseg;
align = temp;
record_alignment (bss_section, align);
subseg_set (bss_section, 0);
if (align)
frag_align (align, 0);
if (S_GET_SEGMENT (symbolP) == bss_section)
symbolP->sy_frag->fr_symbol = 0;
symbolP->sy_frag = frag_now;
pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size,
(char *) 0);
*pfrag = 0;
S_SET_SEGMENT (symbolP, bss_section);
S_CLEAR_EXTERNAL (symbolP);
subseg_set (old_sec, old_subsec);
}
else
{
allocate_common:
S_SET_VALUE (symbolP, (valueT) size);
S_SET_EXTERNAL (symbolP);
/* should be common, but this is how gas does it for now */
S_SET_SEGMENT (symbolP, &bfd_und_section);
}
}
else
{
input_line_pointer++;
/* @@ Some use the dot, some don't. Can we get some consistency?? */
if (*input_line_pointer == '.')
input_line_pointer++;
/* @@ Some say data, some say bss. */
if (strncmp (input_line_pointer, "bss\"", 4)
&& strncmp (input_line_pointer, "data\"", 5))
{
while (*--input_line_pointer != '"')
;
input_line_pointer--;
goto bad_common_segment;
}
while (*input_line_pointer++ != '"')
;
goto allocate_common;
}
demand_empty_rest_of_line ();
return;
{
bad_common_segment:
p = input_line_pointer;
while (*p && *p != '\n')
p++;
c = *p;
*p = '\0';
as_bad ("bad .common segment %s", input_line_pointer + 1);
*p = c;
input_line_pointer = p;
ignore_rest_of_line ();
return;
}
}
static void
obj_elf_local (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_CLEAR_EXTERNAL (symbolP);
symbolP->local = 1;
if (c == ',')
{
input_line_pointer++;
SKIP_WHITESPACE ();
if (*input_line_pointer == '\n')
c = '\n';
}
}
while (c == ',');
demand_empty_rest_of_line ();
}
static void
obj_elf_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);
symbolP->local = 1;
if (c == ',')
{
input_line_pointer++;
SKIP_WHITESPACE ();
if (*input_line_pointer == '\n')
c = '\n';
}
}
while (c == ',');
demand_empty_rest_of_line ();
}
static segT previous_section;
static int previous_subsection;
void
obj_elf_section (xxx)
int xxx;
{
char *string;
asection *sec;
/* Initialize this with inclusive-or of all flags that can be cleared
by attributes, but not set by them. Also include flags that won't
get set properly in the assembler, but which the user/compiler
shouldn't be expected to set. */
flagword flags = SEC_READONLY | SEC_ALLOC | SEC_RELOC;
/* Initialize this with the default flags to be used if none are
specified. */
flagword default_flags = 0;
SKIP_WHITESPACE ();
/* Get name of section. */
if (*input_line_pointer == '"')
string = demand_copy_C_string (&xxx);
else
{
char *p = input_line_pointer;
char c;
while (0 == strchr ("\n\t,; ", *p))
p++;
c = *p;
*p = 0;
string = xmalloc ((unsigned long) (p - input_line_pointer + 1));
strcpy (string, input_line_pointer);
*p = c;
input_line_pointer = p;
}
if (!strcmp (string, ".rodata"))
default_flags = SEC_ALLOC | SEC_READONLY | SEC_RELOC | SEC_LOAD;
else if (!strcmp (string, ".init")
|| !strcmp (string, ".fini"))
default_flags = SEC_ALLOC | SEC_READONLY | SEC_RELOC | SEC_CODE | SEC_LOAD;
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
flags = default_flags;
while (*input_line_pointer == ',')
{
flagword bit;
unsigned int len;
int inv;
char *p, oldp;
input_line_pointer++;
/* Under i386-svr4, gcc emits a string here. I don't know what this
string is supposed to signify or how to handle it. Ignore it for
now, unless it becomes a problem. */
if (*input_line_pointer == '"')
{
demand_copy_C_string (&xxx);
SKIP_WHITESPACE ();
continue;
}
if (*input_line_pointer != '#' && *input_line_pointer != '@')
{
as_bad ("unrecognized syntax in .section command");
ignore_rest_of_line ();
break;
}
input_line_pointer++;
#define CHECK(X,BIT,NEG) \
if (!strncmp(X,input_line_pointer,len = sizeof(X) - 1)) { \
bit = BIT; inv = NEG; goto match; }
CHECK ("write", SEC_READONLY, 1);
CHECK ("alloc", SEC_ALLOC, 0);
CHECK ("execinstr", SEC_CODE, 1);
CHECK ("progbits", SEC_LOAD, 1);
#undef CHECK
p = input_line_pointer;
while (!is_end_of_line[(unsigned char) *p] && *p != 0 && *p != ',')
p++;
*p = 0;
oldp = *p;
as_bad ("unrecognized section attribute `%s' ignored",
input_line_pointer);
*p = oldp;
continue;
match:
if (inv)
flags &= ~bit;
else
flags |= bit;
input_line_pointer += len;
}
demand_empty_rest_of_line ();
/* If the C string wasn't valid, `string' could be null. */
if (!string)
return;
sec = bfd_get_section_by_name (stdoutput, string);
if (sec == 0)
{
sec = subseg_new (string, 0);
bfd_set_section_flags (stdoutput, sec, flags);
sec->output_section = sec;
}
previous_section = now_seg;
previous_subsection = now_subseg;
subseg_set (sec, 0);
}
void
obj_elf_previous (ignore)
int ignore;
{
if (previous_section == 0)
{
as_bad (".previous without corresponding .section; ignored");
return;
}
subseg_set (previous_section, previous_subsection);
previous_section = 0;
}
static int
obj_elf_write_symbol_p (sym)
symbolS *sym;
{
/* If this is a local symbol, are there any relocations for which
need this symbol? */
/* To find this out, we examine all relocations in all bfd sections
that have relocations. If there is one that references this
symbol, we need to keep this symbol. In this case, we return a
true status. In all other cases, we return a false status. */
if (S_IS_LOCAL (sym))
{
asymbol *bsym = sym->bsym;
bfd *abfd = bsym->the_bfd;
asection *bsec;
for (bsec = abfd->sections; bsec; bsec = bsec->next)
{
struct reloc_cache_entry **rlocs = bsec->orelocation;
int rcnt = bsec->reloc_count;
if (rlocs)
{
int i;
for (i = 0; i < rcnt; i++)
if (rlocs[i]->sym_ptr_ptr
&& rlocs[i]->sym_ptr_ptr[0] == bsym)
return 1;
}
else
{
/* No relocations for this section. Check the seg_info
structure to see if there are any fixups for this
section. */
segment_info_type *seginfo = seg_info (bsec);
fixS *fixp;
for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
if ((fixp->fx_addsy && fixp->fx_addsy->bsym == bsym)
|| (fixp->fx_subsy && fixp->fx_subsy->bsym == bsym))
return 1;
}
}
}
return 0;
}
int
obj_elf_write_symbol (sym)
symbolS *sym;
{
return /* obj_elf_write_symbol_p (sym) || */ !S_IS_LOCAL (sym);
}
int
obj_elf_frob_symbol (sym, punt)
symbolS *sym;
int *punt;
{
#if 0 /* ?? The return value is ignored. Only the value of *punt is
relevant. */
return obj_elf_write_symbol_p (sym);
#endif
/* FIXME: Just return 0 until is fixed. */
return 0;
}
static void
obj_elf_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 ();
}
void
obj_read_begin_hook ()
{
}
void
obj_symbol_new_hook (symbolP)
symbolS *symbolP;
{
#if 0 /* BFD already takes care of this */
elf32_symbol_type *esym = (elf32_symbol_type *) symbolP;
/* There is an Elf_Internal_Sym and an Elf_External_Sym. For now,
just zero them out. */
bzero ((char *) &esym->internal_elf_sym, sizeof (esym->internal_elf_sym));
bzero ((char *) &esym->native_elf_sym, sizeof (esym->native_elf_sym));
bzero ((char *) &esym->tc_data, sizeof (esym->tc_data));
#endif
}
void
obj_elf_version (ignore)
int ignore;
{
char *name;
unsigned int c;
char ch;
char *p;
asection *seg = now_seg;
subsegT subseg = now_subseg;
Elf_Internal_Note i_note;
Elf_External_Note e_note;
asection *note_secp = (asection *) NULL;
int i, len;
SKIP_WHITESPACE ();
if (*input_line_pointer == '\"')
{
++input_line_pointer; /* -> 1st char of string. */
name = input_line_pointer;
while (is_a_char (c = next_char_of_string ()))
;
c = *input_line_pointer;
*input_line_pointer = '\0';
*(input_line_pointer - 1) = '\0';
*input_line_pointer = c;
/* create the .note section */
note_secp = subseg_new (".note", 0);
bfd_set_section_flags (stdoutput,
note_secp,
SEC_HAS_CONTENTS | SEC_READONLY);
/* process the version string */
len = strlen (name);
i_note.namesz = ((len + 1) + 3) & ~3; /* round this to word boundary */
i_note.descsz = 0; /* no description */
i_note.type = NT_VERSION;
p = frag_more (sizeof (e_note.namesz));
md_number_to_chars (p, (valueT) i_note.namesz, 4);
p = frag_more (sizeof (e_note.descsz));
md_number_to_chars (p, (valueT) i_note.descsz, 4);
p = frag_more (sizeof (e_note.type));
md_number_to_chars (p, (valueT) i_note.type, 4);
for (i = 0; i < len; i++)
{
ch = *(name + i);
{
FRAG_APPEND_1_CHAR (ch);
}
}
frag_align (2, 0);
subseg_set (seg, subseg);
}
else
{
as_bad ("Expected quoted string");
}
demand_empty_rest_of_line ();
}
static void
obj_elf_size (ignore)
int ignore;
{
char *name = input_line_pointer;
char c = get_symbol_end ();
char *p;
expressionS exp;
symbolS *sym;
p = input_line_pointer;
*p = c;
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
*p = 0;
as_bad ("expected comma after name `%s' in .size directive", name);
*p = c;
ignore_rest_of_line ();
return;
}
input_line_pointer++;
expression (&exp);
if (exp.X_op == O_absent)
{
as_bad ("missing expression in .size directive");
exp.X_op = O_constant;
exp.X_add_number = 0;
}
*p = 0;
sym = symbol_find_or_make (name);
*p = c;
if (exp.X_op == O_constant)
S_SET_SIZE (sym, exp.X_add_number);
else
{
#if 0
static int warned;
if (!warned)
{
as_tsktsk (".size expressions not yet supported, ignored");
warned++;
}
#endif
}
demand_empty_rest_of_line ();
}
static void
obj_elf_type (ignore)
int ignore;
{
char *name = input_line_pointer;
char c = get_symbol_end ();
char *p;
int type = 0;
symbolS *sym;
p = input_line_pointer;
*p = c;
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
as_bad ("expected comma after name in .type directive");
egress:
ignore_rest_of_line ();
return;
}
input_line_pointer++;
SKIP_WHITESPACE ();
if (*input_line_pointer != '#' && *input_line_pointer != '@')
{
as_bad ("expected `#' or `@' after comma in .type directive");
goto egress;
}
input_line_pointer++;
if (!strncmp ("function", input_line_pointer, sizeof ("function") - 1))
{
type = BSF_FUNCTION;
input_line_pointer += sizeof ("function") - 1;
}
else if (!strncmp ("object", input_line_pointer, sizeof ("object") - 1))
{
input_line_pointer += sizeof ("object") - 1;
}
else
{
as_bad ("unrecognized symbol type, ignored");
goto egress;
}
demand_empty_rest_of_line ();
*p = 0;
sym = symbol_find_or_make (name);
sym->bsym->flags |= type;
}
static void
obj_elf_ident (ignore)
int ignore;
{
static segT comment_section;
segT old_section = now_seg;
int old_subsection = now_subseg;
if (!comment_section)
{
char *p;
comment_section = subseg_new (".comment", 0);
bfd_set_section_flags (stdoutput, comment_section, SEC_HAS_CONTENTS);
p = frag_more (1);
*p = 0;
}
else
subseg_set (comment_section, 0);
stringer (1);
subseg_set (old_section, old_subsection);
}
static void
adjust_stab_sections (abfd, sec, xxx)
bfd *abfd;
asection *sec;
PTR xxx;
{
char *name;
asection *strsec;
char *p;
int strsz, nsyms;
if (strncmp (".stab", sec->name, 5))
return;
if (!strcmp ("str", sec->name + strlen (sec->name) - 3))
return;
name = (char *) alloca (strlen (sec->name) + 4);
strcpy (name, sec->name);
strcat (name, "str");
strsec = bfd_get_section_by_name (abfd, name);
if (strsec)
strsz = bfd_section_size (abfd, strsec);
else
strsz = 0;
nsyms = bfd_section_size (abfd, sec) / 12 - 1;
p = seg_info (sec)->stabu.p;
assert (p != 0);
bfd_h_put_16 (abfd, (bfd_vma) nsyms, p + 6);
bfd_h_put_32 (abfd, (bfd_vma) strsz, p + 8);
}
void
elf_frob_file ()
{
bfd_map_over_sections (stdoutput, adjust_stab_sections, (PTR) 0);
#ifdef elf_tc_symbol
{
int i;
for (i = 0; i < stdoutput->symcount; i++)
elf_tc_symbol (stdoutput, (PTR) (stdoutput->outsymbols[i]),
i + 1);
}
#endif
#ifdef elf_tc_final_processing
elf_tc_final_processing ();
#endif
/* Finally, we must make any target-specific sections. */
#ifdef elf_tc_make_sections
elf_tc_make_sections (stdoutput);
#endif
}