/* GNU PIC general coff functions Copyright (C) 2001, 2002, 2003, 2004, 2005 Craig Franklin This file is part of gputils. gputils 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. gputils 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 gputils; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdhdr.h" #include "libgputils.h" gp_object_type * gp_coffgen_init(void) { gp_object_type *object = NULL; /* allocate memory for the object file */ object = (gp_object_type *)malloc(sizeof(*object)); /* initialize the object */ object->filename = NULL; object->processor = generic; object->class = PROC_CLASS_GENERIC; object->time = (long)time(NULL); object->flags = 0; object->num_sections = 0; object->sections = NULL; object->sections_tail = NULL; object->num_symbols = 0; object->symbols = NULL; object->symbols_tail = NULL; object->next = NULL; return object; } gp_section_type * gp_coffgen_findsection(gp_object_type *object, gp_section_type *start, char *name) { gp_section_type *current = NULL; gp_section_type *found = NULL; if (object == NULL) return NULL; current = start; while (current != NULL) { if ((current->name != NULL) && (strcmp(current->name, name) == 0)) { found = current; break; } current = current->next; } return found; } gp_section_type * gp_coffgen_newsection(char *name) { gp_section_type *new = NULL; /* allocate memory for the section */ new = (gp_section_type *)malloc(sizeof(*new)); /* initialize section */ new->name = strdup(name); new->symbol = NULL; new->flags = 0; new->address = 0; new->size = 0; new->data = i_memory_create(); new->num_reloc = 0; new->relocations = NULL; new->relocations_tail = NULL; new->num_lineno = 0; new->line_numbers = NULL; new->line_numbers_tail = NULL; new->is_used = false; new->number = 0; new->data_ptr = 0; new->reloc_ptr = 0; new->lineno_ptr = 0; new->next = NULL; return new; } gp_section_type * gp_coffgen_addsection(gp_object_type *object, char *name) { gp_section_type *new = NULL; if (object == NULL) return NULL; new = gp_coffgen_newsection(name); if (object->sections == NULL) { /* the list is empty */ object->sections = new; } else { /* append the new object to the end of the list */ object->sections_tail->next = new; } object->sections_tail = new; object->num_sections++; return new; } void gp_coffgen_delsectionsyms(gp_object_type *object, gp_section_type *section) { gp_symbol_type *list; gp_symbol_type *symbol; /* remove all symbols for the section */ list = object->symbols; while (list != NULL) { /* advance the pointer so the symbol can be freed */ symbol = list; list = list->next; if (symbol->section == section) { gp_coffgen_delsymbol(object, symbol); } } return; } gp_section_type * gp_coffgen_delsection(gp_object_type *object, gp_section_type *section) { gp_section_type *list = NULL; gp_section_type *previous = NULL; gp_section_type *removed = NULL; if (object == NULL) return NULL; list = object->sections; while (list != NULL) { if (list == section) { removed = section; if (previous == NULL) { /* removing the first section in the list */ object->sections = list->next; if (object->sections == NULL) { /* there are no sections in the list */ object->sections_tail = NULL; } else if (object->sections->next == NULL) { /* there is one section in the list */ object->sections_tail = object->sections; } } else { previous->next = list->next; if (list->next == NULL) { /* The last section in the list is being removed, so update the tail. */ object->sections_tail = previous; } } break; } previous = list; list = list->next; } object->num_sections--; /* FIXME: gp_coffgen_free_section(second); */ return removed; } gp_reloc_type * gp_coffgen_addreloc(gp_section_type *section) { gp_reloc_type *new = NULL; /* allocate memory for the relocation */ new = (gp_reloc_type *)malloc(sizeof(*new)); new->address = 0; new->symbol = NULL; new->symbol_number = 0; new->offset = 0; new->type = 0; new->next = NULL; if (section->relocations == NULL) { /* the list is empty */ section->relocations = new; } else { section->relocations_tail->next = new; } section->relocations_tail = new; section->num_reloc++; return new; } gp_linenum_type * gp_coffgen_addlinenum(gp_section_type *section) { gp_linenum_type *new = NULL; /* allocate memory for the relocation */ new = (gp_linenum_type *)malloc(sizeof(*new)); new->symbol = NULL; new->line_number = 0; new->address = 0; new->next = NULL; if (section->line_numbers == NULL) { /* the list is empty */ section->line_numbers = new; } else { section->line_numbers_tail->next = new; } section->line_numbers_tail = new; section->num_lineno++; return new; } gp_symbol_type * gp_coffgen_findsymbol(gp_object_type *object, char *name) { gp_symbol_type *current = NULL; gp_symbol_type *found = NULL; if (object == NULL) return NULL; current = object->symbols; while (current != NULL) { if ((current->name != NULL) && (strcmp(current->name, name) == 0)) { found = current; break; } current = current->next; } return found; } gp_aux_type * gp_coffgen_addaux(gp_object_type *object, gp_symbol_type *symbol) { gp_aux_type *new = NULL; gp_aux_type *list = NULL; /* allocate memory for the auxiliary symbol */ new = (gp_aux_type *)malloc(sizeof(*new)); new->next = NULL; if (symbol->aux_list == NULL) { /* the list is empty */ symbol->aux_list = new; } else { /* append the new object to the end of the list */ list = symbol->aux_list; while (list->next != NULL) { list = list->next; } list->next = new; } symbol->num_auxsym += 1; object->num_symbols += 1; return new; } gp_symbol_type * gp_coffgen_addsymbol(gp_object_type *object) { gp_symbol_type *new = NULL; /* allocate memory for the symbol */ new = (gp_symbol_type *)malloc(sizeof(*new)); new->name = NULL; new->value = 0; new->section_number = 0; new->section = NULL; new->type = 0; new->class = 0; new->num_auxsym = 0; new->aux_list = NULL; new->number = object->num_symbols; new->next = NULL; if (object->symbols == NULL) { /* the list is empty */ object->symbols = new; } else { object->symbols_tail->next = new; } object->symbols_tail = new; object->num_symbols += 1; return new; } gp_symbol_type * gp_coffgen_delsymbol(gp_object_type *object, gp_symbol_type *symbol) { gp_symbol_type *list = NULL; gp_symbol_type *previous = NULL; gp_symbol_type *removed = NULL; if (object == NULL) return NULL; list = object->symbols; while (list != NULL) { if (list == symbol) { removed = symbol; if (previous == NULL) { /* removing the first symbol in the list */ object->symbols = list->next; if (object->symbols == NULL) { /* there are no symbols in the list */ object->symbols_tail = NULL; } else if (object->symbols->next == NULL) { /* there is one symbol in the list */ object->symbols_tail = object->symbols; } } else { previous->next = list->next; if (list->next == NULL) { /* The last symbol in the list is being removed, so update the tail. */ object->symbols_tail = previous; } } break; } previous = list; list = list->next; } object->num_symbols -= (symbol->num_auxsym + 1); /* FIXME: gp_coffgen_free_symbol(symbol); */ return removed; } /* Determine if any relocation uses the symbol. */ gp_boolean gp_coffgen_has_reloc(gp_object_type *object, gp_symbol_type *symbol) { gp_section_type *section; gp_reloc_type *relocation; section = object->sections; while (section != NULL) { relocation = section->relocations; while (relocation != NULL) { if (relocation->symbol == symbol) { return true; } relocation = relocation->next; } section = section->next; } return false; } /* Determine if the symbol is global */ gp_boolean gp_coffgen_is_global(gp_symbol_type *symbol) { if ((symbol->class == C_EXT) && (symbol->section_number == N_SCNUM)) { return true; } return false; } /* Determine if the symbol is external */ gp_boolean gp_coffgen_is_external(gp_symbol_type *symbol) { if ((symbol->class == C_EXT) && (symbol->section_number == N_UNDEF)) { return true; } return false; } /* Determine if the symbol is debug */ gp_boolean gp_coffgen_is_debug(gp_symbol_type *symbol) { if (symbol->class == N_DEBUG) { return true; } return false; } /* Determine if the symbol is absolute */ gp_boolean gp_coffgen_is_absolute(gp_symbol_type *symbol) { if (symbol->class == N_ABS) { return true; } return false; } /* allocate a block of section */ gp_section_type * gp_coffgen_blocksec(unsigned int number) { gp_section_type *new = NULL; unsigned int i; if (number == 0) return NULL; /* allocate memory for the sections */ new = (gp_section_type *)malloc(sizeof(*new) * number); /* don't process the last entry */ number--; /* initialize the pointers to create the linked list */ for(i = 0; i < number; i++) new[i].next = &new[i+1]; /* assign the tail of the list */ new[number].next = NULL; return new; } /* allocate a block of relocations */ gp_reloc_type * gp_coffgen_blockrel(unsigned int number) { gp_reloc_type *new = NULL; unsigned int i; if (number == 0) return NULL; /* allocate memory for the relocations */ new = (gp_reloc_type *)malloc(sizeof(*new) * number); /* don't process the last entry */ number--; /* initialize the pointers to create the linked list */ for(i = 0; i < number; i++) new[i].next = &new[i+1]; /* assign the tail of the list */ new[number].next = NULL; return new; } /* allocate a block of line numbers */ gp_linenum_type * gp_coffgen_blockline(unsigned int number) { gp_linenum_type *new = NULL; unsigned int i; if (number == 0) return NULL; /* allocate memory for the symbol */ new = (gp_linenum_type *)malloc(sizeof(*new) * number); /* don't process the last entry */ number--; /* initialize the pointers to create the linked list */ for(i = 0; i < number; i++) new[i].next = &new[i+1]; /* assign the tail of the list */ new[number].next = NULL; return new; } /* allocate a block of symbols */ gp_symbol_type * gp_coffgen_blocksym(unsigned int number) { gp_symbol_type *new = NULL; unsigned int i; if (number == 0) return NULL; /* allocate memory for the symbols */ new = (gp_symbol_type *)calloc(sizeof(*new) * number, sizeof(gp_symbol_type)); /* don't process the last entry */ number--; /* initialize the pointers to create the linked list */ for(i = 0; i < number; i++) { new[i].name = NULL; new[i].next = &new[i+1]; } /* assign the tail of the list */ new[number].name = NULL; new[number].next = NULL; return new; } /* allocate a block of auxiliary symbols */ gp_aux_type * gp_coffgen_blockaux(unsigned int number) { gp_aux_type *new = NULL; unsigned int i; if (number == 0) return NULL; /* allocate memory for the symbols */ new = (gp_aux_type *)calloc(sizeof(*new) * number, sizeof(gp_aux_type)); /* don't process the last entry */ number--; /* initialize the pointers to create the linked list */ for(i = 0; i < number; i++) { new[i].type = AUX_NONE; new[i].next = &new[i+1]; } /* assign the tail of the list */ new[number].next = NULL; return new; } int gp_coffgen_free_section(gp_section_type *section) { gp_reloc_type *relocation; gp_linenum_type *line_number; gp_reloc_type *old_relocation; gp_linenum_type *old_line_number; i_memory_free(section->data); relocation = section->relocations; while (relocation != NULL) { old_relocation = relocation; relocation = relocation->next; free(old_relocation); } line_number = section->line_numbers; while (line_number != NULL) { old_line_number = line_number; line_number = line_number->next; free(old_line_number); } free(section->name); free(section); return 0; } int gp_coffgen_free_symbol(gp_symbol_type *symbol) { gp_aux_type *aux; gp_aux_type *old_aux; int num_auxsym = symbol->num_auxsym; /* free the auxilary symbols */ aux = symbol->aux_list; while (aux != NULL) { old_aux = aux; aux = aux->next; free(old_aux); } free(symbol->name); free(symbol); return num_auxsym; } int gp_coffgen_free(gp_object_type *object) { gp_section_type *section; gp_symbol_type *symbol; gp_section_type *old_section; gp_symbol_type *old_symbol; if (object == NULL) return 1; free(object->filename); section = object->sections; while (section != NULL) { old_section = section; section = section->next; gp_coffgen_free_section(old_section); } symbol = object->symbols; while (symbol != NULL) { old_symbol = symbol; symbol = symbol->next; gp_coffgen_free_symbol(old_symbol); } free(object); return 0; } int gp_determine_aux(gp_symbol_type *symbol) { int aux_type = AUX_NONE; if (strcasecmp(".direct", symbol->name) == 0) { return AUX_DIRECT; } if (strcasecmp(".ident", symbol->name) == 0) { return AUX_IDENT; } switch (symbol->class) { case C_FILE: aux_type = AUX_FILE; break; case C_SECTION: aux_type = AUX_SCN; break; default: aux_type = AUX_NONE; } return aux_type; }