mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-23 19:50:13 +08:00
Initial revision
This commit is contained in:
4
gas/config/h8300.mt
Normal file
4
gas/config/h8300.mt
Normal file
@ -0,0 +1,4 @@
|
||||
TARG_CPU_DEPENDENTS=$(srcdir)/../include/h8300-opcode.h
|
||||
LOCAL_LOADLIBES=$(srcdir)/../bfd/$(srcdir)/libbfd.a
|
||||
TDEFINES=-DBFD -DMANY_SEGMENTS
|
||||
|
537
gas/config/obj-ieee.c
Normal file
537
gas/config/obj-ieee.c
Normal file
@ -0,0 +1,537 @@
|
||||
/* obj-format for ieee-695 records.
|
||||
Copyright (C) 1991 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. */
|
||||
|
||||
|
||||
/*
|
||||
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:
|
||||
size += relax_align(size, frag->fr_offset);
|
||||
}
|
||||
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);
|
||||
|
||||
/* We can't represent complicated things in a reloc yet */
|
||||
/* if (from->fx_addsy == 0 ||
|
||||
from->fx_subsy != 0) abort();
|
||||
*/
|
||||
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;
|
||||
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);
|
||||
ptr->sy_symbol.sy.value += 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();
|
||||
}
|
||||
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_GET_VALUE(x)
|
||||
symbolS *x;
|
||||
{
|
||||
return x->sy_symbol.sy.value;
|
||||
}
|
||||
|
||||
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_SET_VALUE(s,v)
|
||||
symbolS *s;
|
||||
long v;
|
||||
{
|
||||
s->sy_symbol.sy.value = v;
|
||||
}
|
||||
|
||||
S_GET_OTHER(x) { abort() ;}
|
||||
S_IS_DEBUG(x) { abort(); }
|
||||
|
||||
char *segment_name() { abort(); }
|
||||
|
||||
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_new(i,0);
|
||||
while (!is_end_of_line[*p])
|
||||
p++;
|
||||
input_line_pointer = p;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void cons();
|
||||
void s_ignore();
|
||||
|
||||
|
||||
/*
|
||||
* stringer()
|
||||
*
|
||||
* We read 0 or more ',' seperated, double-quoted strings.
|
||||
*
|
||||
* Caller should have checked need_pass_2 is FALSE because we don't check it.
|
||||
*/
|
||||
|
||||
void stringer();
|
||||
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(42);
|
||||
}
|
||||
bfd_set_format(abfd, bfd_object);
|
||||
bfd_set_arch_mach(abfd, bfd_arch_h8300, 0);
|
||||
subseg_new(1,0);
|
||||
subseg_new(2,0);
|
||||
subseg_new(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_new(frchain_ptr->frch_seg, frchain_ptr->frch_subseg);
|
||||
#define SUB_SEGMENT_ALIGN 2
|
||||
frag_align(SUB_SEGMENT_ALIGN,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(); }
|
25
gas/config/obj-ieee.h
Normal file
25
gas/config/obj-ieee.h
Normal file
@ -0,0 +1,25 @@
|
||||
#define BFD 1
|
||||
|
||||
|
||||
#include <bfd.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
asymbol sy;
|
||||
int seg;
|
||||
} obj_symbol_type;
|
||||
|
||||
#define S_GET_NAME(s) (((s)->sy_symbol.sy.name))
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
}
|
||||
object_headers;
|
||||
|
||||
#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE 1
|
||||
|
||||
|
||||
int lineno_rootP;
|
||||
|
||||
|
||||
#define IEEE_STYLE
|
662
gas/config/tc-h8300.c
Normal file
662
gas/config/tc-h8300.c
Normal file
@ -0,0 +1,662 @@
|
||||
/* tc-h8300.c -- Assemble code for the Hitachi h8/300
|
||||
Copyright (C) 1991 Free Software Foundation.
|
||||
|
||||
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. */
|
||||
|
||||
|
||||
/*
|
||||
Written By Steve Chamberlain
|
||||
steve@cygnus.com
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "as.h"
|
||||
#include "bfd.h"
|
||||
#include "h8300-opcode.h"
|
||||
#include <ctype.h>
|
||||
|
||||
char comment_chars[] = { ';',0 };
|
||||
|
||||
/* This table describes all the machine specific pseudo-ops the assembler
|
||||
has to support. The fields are:
|
||||
pseudo-op name without dot
|
||||
function to call to execute this pseudo-op
|
||||
Integer arg to pass to the function
|
||||
*/
|
||||
const pseudo_typeS md_pseudo_table[] = {
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
int md_reloc_size ;
|
||||
|
||||
const char EXP_CHARS[] = "eE";
|
||||
|
||||
/* Chars that mean this number is a floating point constant */
|
||||
/* As in 0f12.456 */
|
||||
/* or 0d1.2345e12 */
|
||||
char FLT_CHARS[] = "rRsSfFdDxXpP";
|
||||
|
||||
|
||||
const relax_typeS md_relax_table[1];
|
||||
|
||||
|
||||
static struct hash_control *opcode_hash_control; /* Opcode mnemonics */
|
||||
static struct hash_control *register_hash_control; /* Register name hash table */
|
||||
|
||||
|
||||
/*
|
||||
This function is called once, at assembler startup time. This should
|
||||
set up all the tables, etc that the MD part of the assembler needs
|
||||
*/
|
||||
|
||||
reloc_howto_type *r16;
|
||||
reloc_howto_type *r8;
|
||||
reloc_howto_type *r8ff;
|
||||
reloc_howto_type *r8pcrel;
|
||||
|
||||
void md_begin ()
|
||||
{
|
||||
bfd_arch_info_struct_type *ai;
|
||||
const struct h8_opcode *opcode;
|
||||
|
||||
opcode_hash_control = hash_new();
|
||||
for (opcode = h8_opcodes; opcode->name; opcode++) {
|
||||
hash_insert(opcode_hash_control, opcode->name, (char *)opcode);
|
||||
}
|
||||
|
||||
ai = bfd_lookup_arch(bfd_arch_h8300,0);
|
||||
|
||||
r16 = ai->reloc_type_lookup(ai, BFD_RELOC_16);
|
||||
r8 = ai->reloc_type_lookup(ai, BFD_RELOC_8);
|
||||
r8ff = ai->reloc_type_lookup(ai, BFD_RELOC_8_FFnn);
|
||||
r8pcrel = ai->reloc_type_lookup(ai, BFD_RELOC_8_PCREL);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct h8_exp {
|
||||
char *e_beg;
|
||||
char *e_end;
|
||||
expressionS e_exp;
|
||||
};
|
||||
struct h8_op
|
||||
{
|
||||
op_enum_type mode;
|
||||
unsigned reg;
|
||||
expressionS exp;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
parse operands
|
||||
WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp
|
||||
r0l,r0h,..r7l,r7h
|
||||
@WREG
|
||||
@WREG+
|
||||
@-WREG
|
||||
#const
|
||||
|
||||
*/
|
||||
|
||||
op_enum_type r8_sord[] = {RS8, RD8};
|
||||
op_enum_type r16_sord[] = {RS16, RD16};
|
||||
op_enum_type rind_sord[] = {RSIND, RDIND};
|
||||
op_enum_type abs_sord[2] = {ABS16SRC, ABS16DST};
|
||||
op_enum_type disp_sord[] = {DISPSRC, DISPDST};
|
||||
/* try and parse a reg name, returns number of chars consumed */
|
||||
int DEFUN(parse_reg,(src, mode, reg, dst),
|
||||
char *src AND
|
||||
op_enum_type *mode AND
|
||||
unsigned int *reg AND
|
||||
int dst)
|
||||
{
|
||||
if (src[0] == 's' && src[1] == 'p') {
|
||||
*mode = r16_sord[dst];
|
||||
*reg = 7;
|
||||
return 2;
|
||||
}
|
||||
if (src[0] == 'c' && src[1] == 'c' && src[2] == 'r') {
|
||||
*mode = CCR;
|
||||
*reg = 0;
|
||||
return 3;
|
||||
}
|
||||
if (src[0] == 'f' && src[1] == 'p') {
|
||||
*mode = r16_sord[dst];
|
||||
*reg = 6;
|
||||
return 2;
|
||||
}
|
||||
if (src[0] == 'r') {
|
||||
if (src[1] >= '0' && src[1] <= '7') {
|
||||
if(src[2] == 'l') {
|
||||
*mode = r8_sord[dst];
|
||||
*reg = (src[1] - '0') + 8;
|
||||
return 3;
|
||||
}
|
||||
if(src[2] == 'h') {
|
||||
*mode = r8_sord[dst];
|
||||
*reg = (src[1] - '0') ;
|
||||
return 3;
|
||||
}
|
||||
*mode = r16_sord[dst];
|
||||
*reg = (src[1] - '0');
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
DEFUN(parse_exp,(s, op),
|
||||
char *s AND
|
||||
expressionS *op)
|
||||
{
|
||||
char *save = input_line_pointer;
|
||||
char *new;
|
||||
segT seg;
|
||||
input_line_pointer = s;
|
||||
seg = expr(0,op);
|
||||
new = input_line_pointer;
|
||||
input_line_pointer = save;
|
||||
if (SEG_NORMAL(seg))
|
||||
return new;
|
||||
switch (seg) {
|
||||
case SEG_ABSOLUTE:
|
||||
case SEG_UNKNOWN:
|
||||
case SEG_DIFFERENCE:
|
||||
case SEG_BIG:
|
||||
case SEG_REGISTER:
|
||||
return new;
|
||||
case SEG_ABSENT:
|
||||
as_bad("Missing operand");
|
||||
return new;
|
||||
default:
|
||||
as_bad("Don't understand operand of type %s", segment_name (seg));
|
||||
return new;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
DEFUN(get_operand,(ptr, op, dst),
|
||||
char **ptr AND
|
||||
struct h8_op *op AND
|
||||
unsigned int dst)
|
||||
{
|
||||
char *src = *ptr;
|
||||
op_enum_type mode;
|
||||
unsigned int num;
|
||||
unsigned int len;
|
||||
op->mode = E;
|
||||
|
||||
while (*src == ' ') src++;
|
||||
len = parse_reg(src, &op->mode, &op->reg, dst);
|
||||
if (len) {
|
||||
*ptr = src + len;
|
||||
return ;
|
||||
}
|
||||
|
||||
if (*src == '@') {
|
||||
src++;
|
||||
if (*src == '-') {
|
||||
src++;
|
||||
len = parse_reg(src, &mode, &num, dst);
|
||||
if (len == 0 || mode != r16_sord[dst]) {
|
||||
as_bad("@- needs word register");
|
||||
}
|
||||
op->mode = RDDEC;
|
||||
op->reg = num;
|
||||
*ptr = src + len;
|
||||
return;
|
||||
}
|
||||
if (*src == '(' && ')') {
|
||||
/* Disp */
|
||||
src++;
|
||||
src = parse_exp(src, &op->exp);
|
||||
|
||||
if (*src == ')') {
|
||||
src++;
|
||||
op->mode = abs_sord[dst];
|
||||
*ptr = src;
|
||||
return;
|
||||
}
|
||||
if (*src != ',') {
|
||||
as_bad("expected @(exp, reg16)");
|
||||
}
|
||||
src++;
|
||||
len = parse_reg(src, &mode, &op->reg, dst);
|
||||
if (len == 0 || mode != r16_sord[dst])
|
||||
{
|
||||
as_bad("expected @(exp, reg16)");
|
||||
}
|
||||
op->mode = disp_sord[dst];
|
||||
src += len;
|
||||
if (*src != ')' && '(') {
|
||||
as_bad("expected @(exp, reg16)");
|
||||
|
||||
}
|
||||
*ptr = src +1;
|
||||
|
||||
return;
|
||||
}
|
||||
len = parse_reg(src, &mode, &num, dst);
|
||||
|
||||
if(len) {
|
||||
src += len;
|
||||
if (*src == '+') {
|
||||
src++;
|
||||
if (mode != RS16) {
|
||||
as_bad("@Rn+ needs word register");
|
||||
}
|
||||
op->mode = RSINC;
|
||||
op->reg = num;
|
||||
*ptr = src;
|
||||
return;
|
||||
}
|
||||
if (mode != r16_sord[dst]) {
|
||||
as_bad("@Rn needs word register");
|
||||
}
|
||||
op->mode =rind_sord[dst];
|
||||
op->reg = num;
|
||||
*ptr = src;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
/* must be a symbol */
|
||||
op->mode = abs_sord[dst];
|
||||
*ptr = parse_exp(src, &op->exp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (*src == '#') {
|
||||
src++;
|
||||
op->mode = IMM16;
|
||||
*ptr = parse_exp(src, &op->exp);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
*ptr = parse_exp(src, &op->exp);
|
||||
op->mode = DISP8;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is the guts of the machine-dependent assembler. STR points to a
|
||||
machine dependent instruction. This funciton is supposed to emit
|
||||
the frags/bytes it assembles to.
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
DEFUN(md_assemble,(str),
|
||||
char *str)
|
||||
{
|
||||
char *op_start;
|
||||
char *op_end;
|
||||
struct h8_opcode * opcode;
|
||||
/* Drop leading whitespace */
|
||||
while (*str == ' ')
|
||||
str++;
|
||||
|
||||
|
||||
/* find the op code end */
|
||||
for (op_start = op_end = str;
|
||||
*op_end != 0 && *op_end != ' ';
|
||||
op_end ++)
|
||||
;
|
||||
|
||||
if (op_end == op_start) {
|
||||
as_bad("can't find opcode ");
|
||||
}
|
||||
*op_end = 0;
|
||||
opcode = (struct h8_opcode *) hash_find(opcode_hash_control,
|
||||
op_start);
|
||||
|
||||
if (opcode == NULL) {
|
||||
as_bad("unknown opcode");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
int ok = 1;
|
||||
int j,i;
|
||||
int dispreg = 0;
|
||||
struct h8_op operand[2];
|
||||
char *ptr = op_end+1;
|
||||
if (opcode->noperands)
|
||||
get_operand(& ptr, &operand[0],0);
|
||||
else operand[0].mode = 0;
|
||||
if (opcode->noperands==2) {
|
||||
if (*ptr == ',') ptr++;
|
||||
get_operand(& ptr, &operand[1], 1);
|
||||
}
|
||||
else operand[1].mode = 0;
|
||||
|
||||
|
||||
|
||||
{
|
||||
struct h8_opcode *this_try ;
|
||||
int found = 0;
|
||||
for (j = 0; j < opcode->nopcodes && !found; j++) {
|
||||
this_try = opcode + j;
|
||||
for (i = 0; i < opcode->noperands; i++) {
|
||||
op_enum_type op = (this_try->args.nib[i]) & ~(B30|B31);
|
||||
switch (op) {
|
||||
case Hex0:
|
||||
case Hex1:
|
||||
case Hex2:
|
||||
case Hex3:
|
||||
case Hex4:
|
||||
case Hex5:
|
||||
case Hex6:
|
||||
case Hex7:
|
||||
case Hex8:
|
||||
case Hex9:
|
||||
case HexA:
|
||||
case HexB:
|
||||
case HexC:
|
||||
case HexD:
|
||||
case HexE:
|
||||
case HexF:
|
||||
break;
|
||||
case DISPSRC:
|
||||
case DISPDST:
|
||||
dispreg = operand[i].reg;
|
||||
case RD8:
|
||||
case RS8:
|
||||
case RDIND:
|
||||
case RSIND:
|
||||
case RD16:
|
||||
case RS16:
|
||||
case CCR:
|
||||
case RSINC:
|
||||
case RDDEC:
|
||||
if (operand[i].mode != op) goto fail;
|
||||
break;
|
||||
case KBIT:
|
||||
case IMM8:
|
||||
case IMM16:
|
||||
case IMM3:
|
||||
if (operand[i].mode != IMM16) goto fail;
|
||||
break;
|
||||
case ABS16SRC:
|
||||
case ABS8SRC:
|
||||
if (operand[i].mode != ABS16SRC) goto fail;
|
||||
break;
|
||||
case ABS16DST:
|
||||
case ABS8DST:
|
||||
if (operand[i].mode != ABS16DST) goto fail;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
found =1;
|
||||
fail: ;
|
||||
}
|
||||
if (found == 0)
|
||||
as_bad("illegal operands for opcode");
|
||||
|
||||
|
||||
/* Now we know what sort of opcodes etc, lets build the bytes -
|
||||
actually we know how big the instruction will be too. So we
|
||||
can get
|
||||
*/
|
||||
{
|
||||
char *output = frag_more(this_try->length);
|
||||
char *output_ptr = output;
|
||||
op_enum_type *nibble_ptr = this_try->data.nib;
|
||||
char part;
|
||||
op_enum_type c;
|
||||
char high;
|
||||
int nib;
|
||||
top: ;
|
||||
while (*nibble_ptr != E) {
|
||||
int nibble;
|
||||
for (nibble = 0; nibble <2; nibble++) {
|
||||
c = *nibble_ptr & ~(B30|B31);
|
||||
switch (c) {
|
||||
default:
|
||||
abort();
|
||||
|
||||
case 0:
|
||||
case 1:
|
||||
case 2: case 3: case 4: case 5: case 6:
|
||||
case 7: case 8: case 9: case 10: case 11:
|
||||
case 12: case 13: case 14: case 15:
|
||||
nib = c;
|
||||
break;
|
||||
case DISPREG:
|
||||
nib = dispreg;
|
||||
break;
|
||||
case IMM8:
|
||||
/* if no symbol then put value in place */
|
||||
if (operand[0].exp.X_add_symbol == 0) {
|
||||
operand[0].mode = 0; /* stop it making a fix */
|
||||
*output_ptr++ = (operand[0].exp.X_add_number);
|
||||
nibble_ptr += 2;
|
||||
goto top;
|
||||
}
|
||||
nib = 0;
|
||||
break;
|
||||
|
||||
case DISPDST:
|
||||
/* if no symbol then put value in place */
|
||||
if (operand[1].exp.X_add_symbol == 0) {
|
||||
operand[1].mode = 0; /* stop it making a fix */
|
||||
*output_ptr++ =(operand[1].exp.X_add_number)>>8;
|
||||
*output_ptr++ = (operand[1].exp.X_add_number);
|
||||
nibble_ptr += 4;
|
||||
goto top;
|
||||
}
|
||||
|
||||
nib = 0;
|
||||
break;
|
||||
case IMM3:
|
||||
|
||||
if (operand[0].exp.X_add_symbol == 0) {
|
||||
operand[0].mode = 0; /* stop it making a fix */
|
||||
nib = (operand[0].exp.X_add_number);
|
||||
}
|
||||
else as_bad("can't have symbol for bit number");
|
||||
break;
|
||||
|
||||
case DISPSRC:
|
||||
case IMM16:
|
||||
/* if no symbol then put value in place */
|
||||
if (operand[0].exp.X_add_symbol == 0) {
|
||||
operand[0].mode = 0; /* stop it making a fix */
|
||||
*output_ptr++ =(operand[0].exp.X_add_number)>>8;
|
||||
*output_ptr++ = (operand[0].exp.X_add_number);
|
||||
nibble_ptr += 4;
|
||||
goto top;
|
||||
}
|
||||
|
||||
|
||||
case ABS16SRC:
|
||||
case ABS16DST:
|
||||
|
||||
case ABS8DST:
|
||||
case ABS8SRC:
|
||||
case IGNORE:
|
||||
|
||||
|
||||
nib = 0;
|
||||
break;
|
||||
case DISP8:
|
||||
nib = 0;
|
||||
break;
|
||||
|
||||
|
||||
case RS8:
|
||||
case RS16:
|
||||
case RSIND:
|
||||
case RSINC:
|
||||
case RDIND:
|
||||
nib= operand[0].reg;
|
||||
break;
|
||||
case RD8:
|
||||
case RD16:
|
||||
case RDDEC:
|
||||
nib = operand[1].reg;
|
||||
|
||||
break;
|
||||
case E:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
if (*nibble_ptr & B31) nib|=0x8;
|
||||
if (nibble == 0) {
|
||||
*output_ptr = nib << 4;
|
||||
}
|
||||
else {
|
||||
*output_ptr |= nib;
|
||||
output_ptr++;
|
||||
}
|
||||
nibble_ptr++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* output any fixes */
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 2; i++) {
|
||||
switch (operand[i].mode) {
|
||||
case 0:
|
||||
break;
|
||||
case DISP8:
|
||||
fix_new(frag_now,
|
||||
output+1,
|
||||
1,
|
||||
operand[i].exp.X_add_symbol,
|
||||
operand[i].exp.X_subtract_symbol,
|
||||
operand[i].exp.X_add_number,
|
||||
0,
|
||||
(int)r8pcrel);
|
||||
break;
|
||||
case ABS16SRC:
|
||||
case ABS16DST:
|
||||
case IMM16:
|
||||
case DISPSRC:
|
||||
case DISPDST:
|
||||
fix_new(frag_now,
|
||||
output+2,
|
||||
2,
|
||||
operand[i].exp.X_add_symbol,
|
||||
operand[i].exp.X_subtract_symbol,
|
||||
operand[i].exp.X_add_number,
|
||||
0,
|
||||
(int)r16);
|
||||
break;
|
||||
case RS8:
|
||||
case RD8:
|
||||
case RS16:
|
||||
case RD16:
|
||||
case RDDEC:
|
||||
case RSINC:
|
||||
case RDIND:
|
||||
case RSIND:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DEFUN(tc_crawl_symbol_chain, (headers),
|
||||
object_headers *headers)
|
||||
{
|
||||
printf("call to tc_crawl_symbol_chain \n");
|
||||
}
|
||||
|
||||
symbolS *DEFUN(md_undefined_symbol,(name),
|
||||
char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
DEFUN(tc_headers_hook,(headers),
|
||||
object_headers *headers)
|
||||
{
|
||||
printf("call to tc_headers_hook \n");
|
||||
}
|
||||
void
|
||||
DEFUN_VOID(md_end)
|
||||
{
|
||||
}
|
||||
|
||||
/* Various routines to kill one day */
|
||||
|
||||
char *md_atof () { printf("call to md_atof \n"); abort(); }
|
||||
int md_parse_option () { printf("call to md_parse_option \n"); abort(); }
|
||||
|
||||
int md_short_jump_size;
|
||||
|
||||
void tc_aout_fix_to_chars () { printf("call to tc_aout_fix_to_chars \n");
|
||||
abort(); }
|
||||
void md_create_long_jump () { printf("call to md_create_long_jump \n");
|
||||
abort(); }
|
||||
void md_convert_frag () { printf("call to md_convert_frag \n"); abort(); }
|
||||
|
||||
long
|
||||
DEFUN(md_section_align,(seg, size),
|
||||
segT seg AND
|
||||
long size)
|
||||
{
|
||||
return((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg]));
|
||||
|
||||
}
|
||||
|
||||
void md_apply_fix () { printf("call to md_apply_fix \n"); abort(); }
|
||||
|
||||
void DEFUN(md_operand, (expressionP),expressionS *expressionP)
|
||||
{ }
|
||||
|
||||
int md_long_jump_size;
|
||||
int md_estimate_size_before_relax () { printf("call tomd_estimate_size_before_relax \n"); abort(); }
|
||||
/* Put number into target byte order */
|
||||
void DEFUN(md_number_to_chars,(ptr, use, nbytes),
|
||||
char *ptr AND
|
||||
int use AND
|
||||
unsigned int nbytes)
|
||||
{
|
||||
switch (nbytes) {
|
||||
case 4: *ptr++ = (use >> 24) & 0xff;
|
||||
case 3: *ptr++ = (use >> 16) & 0xff;
|
||||
case 2: *ptr++ = (use >> 8) & 0xff;
|
||||
case 1: *ptr++ = (use >> 0) & 0xff;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
long md_pcrel_from () { printf("call to md_pcrel_from \n"); abort(); }
|
||||
void md_create_short_jump () { printf("call to md_create_short_jump \n");
|
||||
abort(); }
|
||||
|
||||
void tc_coff_symbol_emit_hook() { }
|
Reference in New Issue
Block a user