amigaos-binutils/gas/config/obj-amigahunk.c

278 lines
7.1 KiB
C

/* AmigaOS object file format
Copyright (C) 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, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include "as.h"
enum {
N_UNDF=0,
/*N_ABS=2,*/
/*N_TEXT=4,*/
/*N_DATA=6,*/
/*N_BSS=8,*/
N_INDR=0xa,
/*N_COMM=0x12,*/
N_SETA=0x14,
N_SETT=0x16,
N_SETD=0x18,
N_SETB=0x1a,
/*N_SETV=0x1c,*/
N_WARNING=0x1e,
/*N_FN=0x1f*/
N_EXT=1,
N_TYPE=0x1e,
/*N_STAB=0xe0,*/
};
static void obj_amiga_line PARAMS ((int));
static void obj_amiga_weak PARAMS ((int));
static void obj_amiga_section PARAMS((int));
static char * obj_amiga_section_name PARAMS ((void));
const pseudo_typeS obj_pseudo_table[] =
{
{"line", obj_amiga_line, 0}, /* source code line number */
{"weak", obj_amiga_weak, 0}, /* mark symbol as weak. */
{"2byte", cons, 2},
{"4byte", cons, 4},
{"8byte", cons, 8},
{"hidden", s_ignore, 0},
{"local", s_ignore, 0},
{"section", obj_amiga_section, 0},
{"section.s", obj_amiga_section, 0},
{"sect", obj_amiga_section, 0},
{"sect.s", obj_amiga_section, 0},
{"swbeg", s_ignore, 0},
/* other stuff */
{"ABORT", s_abort, 0},
{NULL, NULL, 0} /* end sentinel */
};
#ifdef BFD_ASSEMBLER
void
obj_amiga_frob_symbol (sym, punt)
symbolS *sym;
int *punt ATTRIBUTE_UNUSED;
{
sec_ptr sec = S_GET_SEGMENT (sym);
unsigned int type = amiga_symbol (symbol_get_bfdsym (sym))->type;
/* Only frob simple symbols this way right now. */
if (! (type & ~ (N_TYPE | N_EXT)))
{
if (type == (N_UNDF | N_EXT)
&& sec == &bfd_abs_section)
{
sec = bfd_und_section_ptr;
S_SET_SEGMENT (sym, sec);
}
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 (symbol_get_bfdsym (sym)->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. */
symbol_get_bfdsym (sym)->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. */
S_SET_SEGMENT (sym, bfd_ind_section_ptr);
symbol_get_bfdsym (sym)->flags |= BSF_INDIRECT;
if (type & N_EXT)
{
symbol_get_bfdsym (sym)->flags |= BSF_EXPORT;
symbol_get_bfdsym (sym)->flags &=~ BSF_LOCAL;
}
break;
case N_WARNING:
/* Mark warning symbols. */
symbol_get_bfdsym (sym)->flags |= BSF_WARNING;
break;
}
}
else
{
symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
}
amiga_symbol (symbol_get_bfdsym (sym))->type = type;
/* Double check weak symbols. */
if (S_IS_WEAK (sym))
{
if (S_IS_COMMON (sym))
as_bad (_("Symbol `%s' can not be both weak and common"),
S_GET_NAME (sym));
}
}
void
obj_amiga_frob_file_before_fix ()
{
/* 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;
bfd_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);
}
#endif /* BFD_ASSEMBLER */
/* Get name of section. */
static char *
obj_amiga_section_name ()
{
char *name;
SKIP_WHITESPACE ();
if (*input_line_pointer == '"')
{
int dummy;
name = demand_copy_C_string (&dummy);
if (name == NULL)
{
ignore_rest_of_line ();
return NULL;
}
}
else
{
char *end = input_line_pointer;
while (0 == strchr ("\n\t,; ", *end))
end++;
if (end == input_line_pointer)
{
as_warn (_("missing name"));
ignore_rest_of_line ();
return NULL;
}
name = xmalloc (end - input_line_pointer + 1);
memcpy (name, input_line_pointer, end - input_line_pointer);
name[end - input_line_pointer] = '\0';
input_line_pointer = end;
}
SKIP_WHITESPACE ();
return name;
}
static void obj_amiga_section(int push) {
char const * name = obj_amiga_section_name();
if (name == NULL)
return;
if (0 == strcmp(".rodata", name))
s_text();
else
s_data();
}
static void
obj_amiga_line (ignore)
int ignore ATTRIBUTE_UNUSED;
{
/* 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_amiga_line() */
/* Handle .weak. This is a GNU extension. */
static void
obj_amiga_weak (ignore)
int ignore ATTRIBUTE_UNUSED;
{
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 ();
}