| /* obj-format for ieee-695 records. |
| Copyright (C) 1991, 92, 93, 94, 95, 1997, 1998 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 */ |