Source file: /~heha/hs/gputils64-210929.zip/gpasm/coff.cpp

/* Generate coff file
   Copyright 2002-2005	Craig Franklin
*/

#include "stdhdr.h"

#include "libgputils.h"
#include "gpasm.h"
#include "gpmsg.h"
#include "coff.h"

/*------------------------------------------------------------------------------------------------*/

static void
_update_section_symbol(gp_section_t *Section)
{
  /* write data to the auxiliary section symbol */
  Section->symbol->aux_list.first->_aux_symbol._aux_scn.length  = Section->size;
  Section->symbol->aux_list.first->_aux_symbol._aux_scn.nreloc  = Section->relocation_list.num_nodes;
  Section->symbol->aux_list.first->_aux_symbol._aux_scn.nlineno = Section->line_number_list.num_nodes;
}

/*------------------------------------------------------------------------------------------------*/

static void _update_reloc_ptr() {
  gp_section_t *section;
  gp_reloc_t   *reloc;
  char          buffer[BUFSIZ];

  section = state.obj.object->section_list.first;
  while (section) {
    reloc = section->relocation_list.first;
    while (reloc) {
      FOR(gp_symbol_list_t,symbol,state.obj.object->symbol_list) {
        if (reloc->symbol_number == symbol->number) {
          reloc->symbol = &*symbol;
          goto rel_next;
        }
      }

      snprintf(buffer, sizeof(buffer), "%s() -- Unknown relocation symbol number: %u\n", "_update_reloc_ptr", reloc->symbol_number);
      gpmsg0(GPE_INTERNAL, buffer);
      exit(1);

rel_next:
      reloc = reloc->next;
    }

    section = section->next;
  }
}

/*------------------------------------------------------------------------------------------------*/

static void _new_config_section(const char *Name, unsigned Address, unsigned Flags, MemBlock_t *Data) {
  state.obj.symbol_num += 2;

  /* increment the section number */
  state.obj.section_num++;

  /* store the flags so they are available for pass 1 */
  state.obj.flags = Flags;

  if (!state.obj.enabled) {
    state.byte_addr = Address;
    return;
  }

  assert(state.obj.object);

  state.obj.section                 = gp_coffgen_add_section(state.obj.object, Name, Data);
  state.obj.section->address        = Address;
  state.obj.section->shadow_address = Address;
  state.obj.section->flags          = Flags;

  /* Add a section symbol, the section number modified later. */
  gp_symbol_list_t::iterator pnew = state.obj.object->gp_coffgen_add_symbol(Name, state.obj.section_num);
  pnew->value   = IS_RAM_ORG ? Address : gp_processor_insn_from_byte_c(state.device.pclass, Address);
  pnew->section = state.obj.section;
  pnew->pclass  = C_SECTION;

  state.obj.section->symbol = pnew;

  gp_aux_t*new_aux = gp_coffgen_add_aux(state.obj.object, &*pnew);
  new_aux->type = AUX_SECTION;
}

/*------------------------------------------------------------------------------------------------*/

static void _create_config_sections() {
  const conf_mem_block_t *conf_sec_mem;
  gp_linenum_t           *linenum;
  char                    section_name[BUFSIZ];
  char                   *upper;

  conf_sec_mem = state.conf_sec_mem;
  while (conf_sec_mem) {
    upper = gp_strdup_upper_case(state.obj_file_name);
    snprintf(section_name, sizeof(section_name), ".config_%0*X_%s", state.device.pclass->addr_digits,
             gp_processor_insn_from_byte_c(state.device.pclass, conf_sec_mem->addr), upper);
    free(upper);

    _new_config_section(section_name, conf_sec_mem->addr,
                        STYP_ABS | ((conf_sec_mem->new_config) ? STYP_DATA_ROM : STYP_TEXT),
                        conf_sec_mem->m);

    if (!state.obj.enabled) {
      return;
    }

    state.obj.section->size      = (conf_sec_mem->new_config) ? gp_processor_byte_from_insn_c(state.device.pclass, 1) : 2;
    state.lst.line.was_byte_addr = conf_sec_mem->addr;

    if (state.debug_info && (state.obj.debug_file == NULL)) {
      gpmsg0(GPE_UNKNOWN, "The .file directive required to generate debug info.");
      return;
    }

    linenum = gp_coffgen_add_linenum(state.obj.section);
    linenum->symbol      = conf_sec_mem->file_symbol;
    /* MPASM(X) bug compatibility */
    linenum->line_number = (state.mpasm_compatible) ? (state.src_list.last->line_number - 1) : conf_sec_mem->line_number;
    linenum->address     = conf_sec_mem->addr;

    _update_section_symbol(state.obj.section);
    conf_sec_mem = conf_sec_mem->next;
  }
}

/*------------------------------------------------------------------------------------------------*/

void coff_init(void) {
  if (state.obj_file != OUT_NAMED) {
    snprintf(state.obj_file_name, sizeof(state.obj_file_name), "%s.o", state.base_file_name);
  }

  if (state.obj_file == OUT_SUPPRESS) {
    state.obj.enabled = false;
    unlink(state.obj_file_name);
  }
  else {
    if (!state.processor_chosen) {
      state.obj.enabled = false;
    }
    else {
      state.obj.object = gp_coffgen_new_object(state.obj_file_name);
      state.obj.object->processor = state.processor;
      state.obj.object->pclass     = state.device.pclass;
      state.obj.object->isnew     = state.obj.newcoff;
      state.obj.enabled           = true;
    }
  }
}

/*------------------------------------------------------------------------------------------------*/

void coff_cleanup_before_eof(void) {
  if (!state.obj.enabled) {
    return;
  }

  /* store data from the last section */
  coff_close_section();

  /* update relocation symbol pointers */
  _update_reloc_ptr();

  /* combine overlayed sections */
  gp_cofflink_combine_overlay(state.obj.object, 1);

  if (state.mode == MODE_RELOCATABLE) {
    /* create config_sections */
    _create_config_sections();
  }
}

/*------------------------------------------------------------------------------------------------*/

void coff_close_file(void) {
  if (!state.obj.enabled) {
    return;
  }

  if (!gp_writeobj_write_coff(state.obj.object, (state.num.errors + gp_num.errors))) {
    gpmsg0(GPE_UNKNOWN, "System error while writing object file.");
    exit(1);
  }

  gp_coffgen_free_object(state.obj.object);
}

/*------------------------------------------------------------------------------------------------*/

void coff_new_section(const char *Name, unsigned Address, unsigned Flags) {
  gp_section_t *found;
  gp_aux_t     *new_aux;

  state.obj.symbol_num += 2;

  /* increment the section number */
  state.obj.section_num++;

  /* store the flags so they are available for pass 1 */
  state.obj.flags = Flags;

  if (!state.obj.enabled) {
    state.byte_addr = Address;
    return;
  }

  assert(state.obj.object);

  /* store data from the last section */
  coff_close_section();

  found = gp_coffgen_find_section(state.obj.object, state.obj.object->section_list.first, Name);
  if (found) {
    if (FlagIsSet(Flags, STYP_OVERLAY) && FlagIsSet(found->flags, STYP_OVERLAY)) {
      /* Overlayed sections can be duplicated. This allows multiple code
         sections in the same source file to share the same data memory. */
      if ((Flags != found->flags) || (Address != found->address)) {
        gpmsg(GPE_CONTIG_SECTION, NULL, Name);
        return;
      }
    }
     else {
      gpmsg(GPE_CONTIG_SECTION, NULL, Name);
      return;
    }
  }

  state.obj.section = gp_coffgen_add_section(state.obj.object, Name, NULL);
  state.obj.section->address        = Address;
  state.obj.section->shadow_address = Address;
  state.obj.section->flags          = Flags;

  /* Add a section symbol, the section number modified later. */
  gp_symbol_list_t::iterator pnew = state.obj.object->gp_coffgen_add_symbol(Name, state.obj.section_num);
  pnew->value   = IS_RAM_ORG ? Address : gp_processor_insn_from_byte_c(state.device.pclass, Address);
  pnew->section = state.obj.section;
  pnew->pclass   = C_SECTION;

  state.obj.section->symbol = pnew;

  new_aux       = gp_coffgen_add_aux(state.obj.object, &*pnew);
  new_aux->type = AUX_SECTION;

  state.i_memory  = state.obj.section->data;
  state.byte_addr = Address;
}

/*------------------------------------------------------------------------------------------------*/

void coff_close_section(void) {
  if (state.obj.section == NULL) {
    return;
  }

  state.obj.section->size = state.byte_addr - state.obj.section->address;
  _update_section_symbol(state.obj.section);
}

/*------------------------------------------------------------------------------------------------*/

/* Add a symbol to the coff symbol table.  The calling function must
   increment the global symbol number. */

gp_symbol_t*coff_add_sym(const char *Name, gpasmVal Value, enum gpasmValTypes Type, int Section_number) {
  if (!state.obj.enabled) return 0;
  unsigned  pclass;
  if (!set_symbol_attr(NULL, &pclass, Type)) return 0;
  gp_symbol_list_t::iterator symbol = state.obj.object->gp_coffgen_find_symbol(Name);
  /* verify the duplicate extern has the same properties */
  if (&*symbol) {
    if (Type == VAL_EXTERNAL)  {
      if ((symbol->type != Type) || (symbol->pclass != pclass) || (symbol->section_number != Section_number)) {
        char message[BUFSIZ];
        snprintf(message, sizeof(message),
                 "Duplicate label or redefining symbol that cannot be redefined: \"%s\"", Name);
        gpmsg0(GPE_UNKNOWN, message);
      }
    }
    /* (Type != VAL_EXTERNAL) */
    else if (Type != VAL_DEBUG) {
      char message[BUFSIZ];
      snprintf(message, sizeof(message),
               "Duplicate label or redefining symbol that cannot be redefined: \"%s\"", Name);
      gpmsg0(GPE_DUPLAB, message);
    }
  }
  else {
    symbol = state.obj.object->gp_coffgen_add_symbol(Name, Section_number);
    symbol->value   = Value;
    symbol->section = state.obj.section;
    symbol->pclass   = pclass;
  }

  return &*symbol;
}

/*------------------------------------------------------------------------------------------------*/

/* All coff data is generated on the second pass. To support forward
   references to symbols in the relocation table, the symbol index
   is stored in relocations instead of a pointer to the symbol. Before
   the coff is written the symbol pointer is updated. */

void coff_add_reloc(unsigned Symbol_number, int Offset, uint16_t Type) {
  gp_reloc_t   *reloc;
  unsigned  origin;

  if ((!state.obj.enabled) || (state.obj.section == NULL)) {
    return;
  }

  origin = state.byte_addr - state.obj.section->address;

  reloc = gp_coffgen_add_reloc(state.obj.section);
  reloc->address       = origin;
  reloc->symbol_number = Symbol_number;
  reloc->offset        = Offset;
  reloc->type          = Type;
}

/*------------------------------------------------------------------------------------------------*/

void coff_add_linenum(unsigned Emitted) {
  static bool  show_bad_debug = true;

  gp_linenum_t      *linenum;
  unsigned       end;
  unsigned       origin;

  if ((!state.obj.enabled) || (state.obj.section == NULL)) {
    return;
  }

  /* If the section is absolute, use the abolute address, */
  origin = state.lst.line.was_byte_addr;
  if (FlagIsClr(state.obj.section->flags, STYP_ABS)) {
    /* else use the relative address. */
    origin -= state.obj.section->address;
  }

  if (state.debug_info && (state.obj.debug_file == NULL)) {
    if (show_bad_debug) {
      gpmsg0(GPE_UNKNOWN, "The .file directive required to generate debug info.");
      show_bad_debug = false;
    }
    return;
  }

  end = origin + Emitted;
  while (origin < end) {
    linenum = gp_coffgen_add_linenum(state.obj.section);

    if (state.debug_info) {
      linenum->symbol      = state.obj.debug_file;
      linenum->line_number = state.obj.debug_line;
    }
     else {
      linenum->symbol      = state.src_list.last->file_symbol;
      linenum->line_number = state.src_list.last->line_number;
    }

    linenum->address = origin;

    origin += (origin & 1) ? 1 : 2;
  }
}

/*------------------------------------------------------------------------------------------------*/

/* coff_add_file_sym -- Add a ".file" symbol to the coff symbol table. */

gp_symbol_t* coff_add_file_sym(const char *File_name, bool Is_include) {
  gp_symbol_t *symbol;
  gp_aux_t    *aux;

  state.obj.symbol_num += 2;

  if (!state.obj.enabled) {
    return NULL;
  }

  /* add .file symbol */
  symbol = &*state.obj.object->gp_coffgen_add_symbol(".file", N_DEBUG);
  symbol->pclass = C_FILE;

  aux = gp_coffgen_add_aux(state.obj.object, symbol);
  aux->type                           = AUX_FILE;
  aux->_aux_symbol._aux_file.filename = GP_Strdup(File_name);

  if (Is_include) {
    aux->_aux_symbol._aux_file.line_number = state.src_list.last->line_number - 1;
  }
  else {
    aux->_aux_symbol._aux_file.line_number = 0;
  }

  aux->_aux_symbol._aux_file.flags = 0;
  return symbol;
}

/*------------------------------------------------------------------------------------------------*/

/* coff_add_eof_sym - Add an ".eof" symbol to the coff symbol table. */

void coff_add_eof_sym()
{
  gp_symbol_t *symbol;

  state.obj.symbol_num++;

  if (!state.obj.enabled) {
    return;
  }

  /* add .eof symbol */
  symbol = &*state.obj.object->gp_coffgen_add_symbol(".eof", N_DEBUG);
  symbol->pclass = C_EOF;
}

/*------------------------------------------------------------------------------------------------*/

/* coff_add_list_sym - Add a ".list" symbol to the coff symbol table. */

void coff_add_list_sym(const char*name) {
  if (state.debug_info) return;
  state.obj.symbol_num++;
  if (!state.obj.enabled) return;
  /* add .list symbol */
  gp_symbol_list_t::iterator sym = state.obj.object->gp_coffgen_add_symbol(name, N_DEBUG);
  sym->value = state.src_list.last->line_number;
  sym->pclass = C_LIST;
}

/*------------------------------------------------------------------------------------------------*/

/* coff_add_direct_sym - Add a ".direct" symbol to the coff symbol table. */

void coff_add_direct_sym(uint8_t Command, const char *String) {
  state.obj.symbol_num += 2;
  if (!state.obj.enabled) return;
  /* add .direct symbol */
  gp_symbol_t*symbol = &*state.obj.object->gp_coffgen_add_symbol(".direct", state.obj.section_num);
  symbol->value   = gp_processor_insn_from_byte_c(state.device.pclass, state.byte_addr);
  symbol->section = state.obj.section;

  gp_aux_t*aux = gp_coffgen_add_aux(state.obj.object, symbol);
  aux->type                            = AUX_DIRECT;
  aux->_aux_symbol._aux_direct.command = Command;
  aux->_aux_symbol._aux_direct.string  = GP_Strdup(String);
}

/*------------------------------------------------------------------------------------------------*/

/* coff_add_ident_sym - Add an ".ident" symbol to the coff symbol table. */

void coff_add_ident_sym(const char *String) {
  state.obj.symbol_num += 2;
  if (!state.obj.enabled) return;
  /* add .ident symbol */
  gp_symbol_t *symbol = &*state.obj.object->gp_coffgen_add_symbol(".ident", N_DEBUG);

  gp_aux_t    *aux = gp_coffgen_add_aux(state.obj.object, symbol);
  aux->type                          = AUX_IDENT;
  aux->_aux_symbol._aux_ident.string = GP_Strdup(String);
}

/*------------------------------------------------------------------------------------------------*/

/* coff_local_name - If the symbol is local, generate a modified name for the coff symbol table. */

char* coff_local_name(const char *Name) {
  if (!state.obj.enabled) return NULL;
  unsigned count = 1;
  char buffer[BUFSIZ];
  symbol_t*local = gp_sym_get_symbol(state.stGlobal, Name);
  if (!local) {
    /* It isn't in the stGlobal so it must be in stTop. It's local. */
    while (true) {
      snprintf(buffer, sizeof(buffer), "_%u%s", count, Name);
      gp_symbol_t*symbol = &*state.obj.object->gp_coffgen_find_symbol(buffer);
      if (!symbol) break;
      count++;
    }
  }
  else {
    gp_strncpy(buffer, Name, sizeof(buffer));
  }

  return GP_Strdup(buffer);
}
Detected encoding: ASCII (7 bit)2