NetBSD/gnu/dist/gas/config/obj-ieee.c

628 lines
12 KiB
C

/* obj-format for ieee-695 records.
Copyright (C) 1991, 92, 93, 94, 95, 1997 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. */
/*
created by
steve chamberlain steve@cygnus.com
*/
/*
this will hopefully become the port through which bfd and gas talk,
for the moment, only ieee is known to work well.
*/
#include "bfd.h"
#include "as.h"
#include "subsegs.h"
#include "output-file.h"
#include "frags.h"
bfd *abfd;
/* How many addresses does the .align take? */
static relax_addressT
relax_align (address, alignment)
register relax_addressT address; /* Address now. */
register long alignment; /* Alignment (binary). */
{
relax_addressT mask;
relax_addressT new_address;
mask = ~((~0) << alignment);
new_address = (address + mask) & (~mask);
return (new_address - address);
} /* relax_align() */
/* calculate the size of the frag chain and create a bfd section
to contain all of it */
static void
DEFUN (size_section, (abfd, idx),
bfd * abfd AND
unsigned int idx)
{
asection *sec;
unsigned int size = 0;
fragS *frag = segment_info[idx].frag_root;
while (frag)
{
if (frag->fr_address != size)
{
printf ("Out of step\n");
size = frag->fr_address;
}
size += frag->fr_fix;
switch (frag->fr_type)
{
case rs_fill:
case rs_org:
size += frag->fr_offset * frag->fr_var;
break;
case rs_align:
case rs_align_code:
{
addressT off;
off = relax_align (size, frag->fr_offset);
if (frag->fr_subtype != 0 && off > frag->fr_subtype)
off = 0;
size += off;
}
}
frag = frag->fr_next;
}
if (size)
{
char *name = segment_info[idx].name;
if (name == (char *) NULL)
{
name = ".data";
}
segment_info[idx].user_stuff = (char *) (sec = bfd_make_section (abfd, name));
/* Make it output through itself */
sec->output_section = sec;
sec->flags |= SEC_HAS_CONTENTS;
bfd_set_section_size (abfd, sec, size);
}
}
/* run through a frag chain and write out the data to go with it */
static void
DEFUN (fill_section, (abfd, idx),
bfd * abfd AND
unsigned int idx)
{
asection *sec = segment_info[idx].user_stuff;
if (sec)
{
fragS *frag = segment_info[idx].frag_root;
unsigned int offset = 0;
while (frag)
{
unsigned int fill_size;
unsigned int count;
switch (frag->fr_type)
{
case rs_fill:
case rs_align:
case rs_org:
if (frag->fr_fix)
{
bfd_set_section_contents (abfd,
sec,
frag->fr_literal,
frag->fr_address,
frag->fr_fix);
}
offset += frag->fr_fix;
fill_size = frag->fr_var;
if (fill_size)
{
unsigned int off = frag->fr_fix;
for (count = frag->fr_offset; count; count--)
{
bfd_set_section_contents (abfd, sec,
frag->fr_literal +
frag->fr_fix,
frag->fr_address + off,
fill_size);
off += fill_size;
}
}
break;
default:
abort ();
}
frag = frag->fr_next;
}
}
}
/* Count the relocations in a chain */
static unsigned int
DEFUN (count_entries_in_chain, (idx),
unsigned int idx)
{
unsigned int nrelocs;
fixS *fixup_ptr;
/* Count the relocations */
fixup_ptr = segment_info[idx].fix_root;
nrelocs = 0;
while (fixup_ptr != (fixS *) NULL)
{
fixup_ptr = fixup_ptr->fx_next;
nrelocs++;
}
return nrelocs;
}
/* output all the relocations for a section */
void
DEFUN (do_relocs_for, (idx),
unsigned int idx)
{
unsigned int nrelocs;
arelent **reloc_ptr_vector;
arelent *reloc_vector;
asymbol **ptrs;
asection *section = (asection *) (segment_info[idx].user_stuff);
unsigned int i;
fixS *from;
if (section)
{
nrelocs = count_entries_in_chain (idx);
reloc_ptr_vector = (arelent **) malloc ((nrelocs + 1) * sizeof (arelent *));
reloc_vector = (arelent *) malloc (nrelocs * sizeof (arelent));
ptrs = (asymbol **) malloc (nrelocs * sizeof (asymbol *));
from = segment_info[idx].fix_root;
for (i = 0; i < nrelocs; i++)
{
arelent *to = reloc_vector + i;
asymbol *s;
reloc_ptr_vector[i] = to;
to->howto = (reloc_howto_type *) (from->fx_r_type);
#if 0 /* We can't represent complicated things in a reloc yet */
if (from->fx_addsy == 0 || from->fx_subsy != 0) abort();
#endif
s = &(from->fx_addsy->sy_symbol.sy);
to->address = ((char *) (from->fx_frag->fr_address +
from->fx_where))
- ((char *) (&(from->fx_frag->fr_literal)));
to->addend = from->fx_offset;
/* If we know the symbol which we want to relocate to, turn
this reloaction into a section relative.
If this relocation is pcrelative, and we know the
destination, we still want to keep the relocation - since
the linker might relax some of the bytes, but it stops
being pc relative and turns into an absolute relocation. */
if (s)
{
if ((s->flags & BSF_UNDEFINED) == 0)
{
to->section = s->section;
/* We can refer directly to the value field here,
rather than using S_GET_VALUE, because this is
only called after do_symbols, which sets up the
value field. */
to->addend += s->value;
to->sym_ptr_ptr = 0;
if (to->howto->pcrel_offset)
{
/* This is a pcrel relocation, the addend should be adjusted */
to->addend -= to->address + 1;
}
}
else
{
to->section = 0;
*ptrs = &(from->fx_addsy->sy_symbol.sy);
to->sym_ptr_ptr = ptrs;
if (to->howto->pcrel_offset)
{
/* This is a pcrel relocation, the addend should be adjusted */
to->addend -= to->address - 1;
}
}
}
else
{
to->section = 0;
}
ptrs++;
from = from->fx_next;
}
/* attatch to the section */
section->orelocation = reloc_ptr_vector;
section->reloc_count = nrelocs;
section->flags |= SEC_LOAD;
}
}
/* do the symbols.. */
static void
DEFUN (do_symbols, (abfd),
bfd * abfd)
{
extern symbolS *symbol_rootP;
symbolS *ptr;
asymbol **symbol_ptr_vec;
asymbol *symbol_vec;
unsigned int count = 0;
unsigned int index;
for (ptr = symbol_rootP;
ptr != (symbolS *) NULL;
ptr = ptr->sy_next)
{
if (SEG_NORMAL (ptr->sy_symbol.seg))
{
ptr->sy_symbol.sy.section =
(asection *) (segment_info[ptr->sy_symbol.seg].user_stuff);
S_SET_VALUE (ptr, S_GET_VALUE (ptr) + ptr->sy_frag->fr_address);
if (ptr->sy_symbol.sy.flags == 0)
{
ptr->sy_symbol.sy.flags = BSF_LOCAL;
}
}
else
{
switch (ptr->sy_symbol.seg)
{
case SEG_ABSOLUTE:
ptr->sy_symbol.sy.flags |= BSF_ABSOLUTE;
ptr->sy_symbol.sy.section = 0;
break;
case SEG_UNKNOWN:
ptr->sy_symbol.sy.flags = BSF_UNDEFINED;
ptr->sy_symbol.sy.section = 0;
break;
default:
abort ();
}
}
ptr->sy_symbol.sy.value = S_GET_VALUE (ptr);
count++;
}
symbol_ptr_vec = (asymbol **) malloc ((count + 1) * sizeof (asymbol *));
index = 0;
for (ptr = symbol_rootP;
ptr != (symbolS *) NULL;
ptr = ptr->sy_next)
{
symbol_ptr_vec[index] = &(ptr->sy_symbol.sy);
index++;
}
symbol_ptr_vec[index] = 0;
abfd->outsymbols = symbol_ptr_vec;
abfd->symcount = count;
}
/* The generic as->bfd converter. Other backends may have special case
code */
void
DEFUN_VOID (bfd_as_write_hook)
{
int i;
for (i = SEG_E0; i < SEG_UNKNOWN; i++)
{
size_section (abfd, i);
}
for (i = SEG_E0; i < SEG_UNKNOWN; i++)
fill_section (abfd, i);
do_symbols (abfd);
for (i = SEG_E0; i < SEG_UNKNOWN; i++)
do_relocs_for (i);
}
S_SET_SEGMENT (x, y)
symbolS *x;
int y;
{
x->sy_symbol.seg = y;
}
S_IS_DEFINED (x)
symbolS *x;
{
if (SEG_NORMAL (x->sy_symbol.seg))
{
return 1;
}
switch (x->sy_symbol.seg)
{
case SEG_UNKNOWN:
return 0;
default:
abort ();
}
}
S_IS_EXTERNAL (x)
{
abort ();
}
S_GET_DESC (x)
{
abort ();
}
S_GET_SEGMENT (x)
symbolS *x;
{
return x->sy_symbol.seg;
}
S_SET_EXTERNAL (x)
symbolS *x;
{
x->sy_symbol.sy.flags |= BSF_GLOBAL | BSF_EXPORT;
}
S_SET_NAME (x, y)
symbolS *x;
char *y;
{
x->sy_symbol.sy.name = y;
}
S_GET_OTHER (x)
{
abort ();
}
S_IS_DEBUG (x)
{
abort ();
}
#ifndef segment_name
char *
segment_name ()
{
abort ();
}
#endif
void
obj_read_begin_hook ()
{
}
static void
obj_ieee_section (ignore)
int ignore;
{
extern char *input_line_pointer;
extern char is_end_of_line[];
char *p = input_line_pointer;
char *s = p;
int i;
/* Look up the name, if it doesn't exist, make it */
while (*p && *p != ' ' && *p != ',' && !is_end_of_line[*p])
{
p++;
}
for (i = SEG_E0; i < SEG_UNKNOWN; i++)
{
if (segment_info[i].hadone)
{
if (strncmp (segment_info[i].name, s, p - s) == 0)
{
goto ok;
}
}
else
break;
}
if (i == SEG_UNKNOWN)
{
as_bad ("too many sections");
return;
}
segment_info[i].hadone = 1;
segment_info[i].name = malloc (p - s + 1);
memcpy (segment_info[i].name, s, p - s);
segment_info[i].name[p - s] = 0;
ok:
subseg_set (i, 0);
while (!is_end_of_line[*p])
p++;
input_line_pointer = p;
}
void cons ();
void s_ignore ();
void s_globl ();
const pseudo_typeS obj_pseudo_table[] =
{
{"section", obj_ieee_section, 0},
{"data.b", cons, 1},
{"data.w", cons, 2},
{"data.l", cons, 4},
{"export", s_globl, 0},
{"option", s_ignore, 0},
{"end", s_ignore, 0},
{"import", s_ignore, 0},
{"sdata", stringer, 0},
0,
};
void
obj_symbol_new_hook (symbolP)
symbolS *symbolP;
{
symbolP->sy_symbol.sy.the_bfd = abfd;
}
#if 1
extern void
DEFUN_VOID (write_object_file)
{
int i;
struct frchain *frchain_ptr;
struct frag *frag_ptr;
abfd = bfd_openw (out_file_name, "ieee");
if (abfd == 0)
{
as_perror ("FATAL: Can't create %s", out_file_name);
exit (EXIT_FAILURE);
}
bfd_set_format (abfd, bfd_object);
bfd_set_arch_mach (abfd, bfd_arch_h8300, 0);
subseg_set (1, 0);
subseg_set (2, 0);
subseg_set (3, 0);
for (frchain_ptr = frchain_root;
frchain_ptr != (struct frchain *) NULL;
frchain_ptr = frchain_ptr->frch_next)
{
/* Run through all the sub-segments and align them up. Also close any
open frags. We tack a .fill onto the end of the frag chain so
that any .align's size can be worked by looking at the next
frag. */
subseg_set (frchain_ptr->frch_seg, frchain_ptr->frch_subseg);
#ifndef SUB_SEGMENT_ALIGN
#define SUB_SEGMENT_ALIGN(SEG) 2
#endif
frag_align (SUB_SEGMENT_ALIGN (now_seg), 0, 0);
frag_wane (frag_now);
frag_now->fr_fix = 0;
know (frag_now->fr_next == NULL);
}
/* Now build one big frag chain for each segment, linked through
fr_next. */
for (i = SEG_E0; i < SEG_UNKNOWN; i++)
{
fragS **prev_frag_ptr_ptr;
struct frchain *next_frchain_ptr;
/* struct frag **head_ptr = segment_info[i].frag_root;*/
segment_info[i].frag_root = segment_info[i].frchainP->frch_root;
#if 0
/* Im not sure what this is for */
for (frchain_ptr = segment_info[i].frchainP->frch_root;
frchain_ptr != (struct frchain *) NULL;
frchain_ptr = frchain_ptr->frch_next)
{
*head_ptr = frchain_ptr;
head_ptr = &frchain_ptr->next;
}
#endif
}
for (i = SEG_E0; i < SEG_UNKNOWN; i++)
{
relax_segment (segment_info[i].frag_root, i);
}
/* Now the addresses of the frags are correct within the segment */
bfd_as_write_hook ();
bfd_close (abfd);
}
#endif
H_SET_TEXT_SIZE (a, b)
{
abort ();
}
H_GET_TEXT_SIZE ()
{
abort ();
}
H_SET_BSS_SIZE ()
{
abort ();
}
H_SET_STRING_SIZE ()
{
abort ();
}
H_SET_RELOCATION_SIZE ()
{
abort ();
}
H_SET_MAGIC_NUMBER ()
{
abort ();
}
H_GET_FILE_SIZE ()
{
abort ();
}
H_GET_TEXT_RELOCATION_SIZE ()
{
abort ();
}
/* end of obj-ieee.c */