/* 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(); }