/* GNU PIC general coff functions
Copyright 2001, 2002, 2003, 2004, 2005
Craig Franklin
Copyright 2016 Molnár Károly
*/
#include "stdhdr.h"
#include "libgputils.h"
#define CHECK_RELOCATIONS_PASS_MAX 20
#define CHECK_RELOCATIONS_DEPTH_MAX 100
static unsigned object_serial_id = 0;
static unsigned section_serial_id = 0;
/*------------------------------------------------------------------------------------------------*/
FUNC(gp_object_t*) gp_coffgen_new_object(const char *File_name) {
/* allocate memory for the object file */
gp_object_t *object = new gp_object_t;
memset(object,0,sizeof*object);
/* initialize the object */
object->filename = GP_Strdup(File_name);
object->processor = gp_find_processor("generic");
object->pclass = PROC_CLASS_GENERIC;
object->time = (uint32_t)time(NULL);
object->serial_id = object_serial_id++;
gp_list_set_delete_node_func(&object->section_list, (gp_node_del_t)gp_coffgen_free_section);
gp_list_set_delete_node_func(&object->dead_section_list, (gp_node_del_t)gp_coffgen_free_section);
gp_list_set_delete_node_func(&object->symbol_list, (gp_node_del_t)gp_coffgen_free_symbol);
gp_list_set_delete_node_func(&object->dead_symbol_list, (gp_node_del_t)gp_coffgen_free_symbol);
return object;
}
/*------------------------------------------------------------------------------------------------*/
/* Move linked lists between two object. */
FUNC(void) gp_coffgen_transfer_object_data(gp_object_t *Receiver, gp_object_t *Sender) {
if ((Receiver == NULL) || (Sender == NULL)) {
return;
}
gp_list_move(&Receiver->section_list, &Sender->section_list);
gp_list_move(&Receiver->dead_section_list, &Sender->dead_section_list);
gp_list_move(&Receiver->symbol_list, &Sender->symbol_list);
gp_list_move(&Receiver->dead_symbol_list, &Sender->dead_symbol_list);
Receiver->num_symbols += Sender->num_symbols;
Sender->num_symbols = 0;
}
/*------------------------------------------------------------------------------------------------*/
/* Update the object identifier in the all internal linked lists. */
FUNC(bool) gp_coffgen_update_all_object_id(gp_object_t *Object) {
gp_section_t *section;
// gp_symbol_t *symbol;
unsigned id;
if (Object == NULL) {
return false;
}
id = Object->serial_id;
section = Object->section_list.first;
while (section) {
section->object_id = id;
section = section->next;
}
section = Object->dead_section_list.first;
while (section) {
section->object_id = id;
section = section->next;
}
gp_symbol_list_t::iterator sit;
for (sit = Object->symbol_list.begin(); sit!=Object->symbol_list.end(); sit++) {
// symbol = Object->symbol_list.first;
// while (symbol) {
// symbol->object_id = id;
sit->object_id = id;
// symbol = symbol->next;
}
// symbol = Object->dead_symbol_list.first;
for (sit = Object->dead_symbol_list.begin(); sit!=Object->dead_symbol_list.end(); sit++) {
// while (symbol) {
// symbol->object_id = id;
sit->object_id = id;
// symbol = symbol->next;
}
return true;
}
/*------------------------------------------------------------------------------------------------*/
/* Find a "Name" section from the given starting section. */
FUNC(gp_section_t*) gp_coffgen_find_section(gp_object_t *Object, gp_section_t *Start, const char *Name) {
gp_section_t *section;
if ((Object == NULL) || (Start == NULL)) {
return NULL;
}
section = Start;
while (section) {
if ((section->name) && (strcmp(section->name, Name) == 0)) {
return section;
}
section = section->next;
}
return NULL;
}
/*------------------------------------------------------------------------------------------------*/
/* Create a pnew section. */
FUNC(gp_section_t*) gp_coffgen_new_section(const char *Name, MemBlock_t *Data) {
gp_section_t *pnew;
/* allocate memory for the section */
pnew = (gp_section_t *)gp_list_node_new(sizeof(gp_section_t));
/* initialize section */
pnew->name = GP_Strdup(Name);
pnew->data = (Data) ? Data : gp_mem_i_create();
pnew->serial_id = section_serial_id++;
return pnew;
}
/*------------------------------------------------------------------------------------------------*/
/* Allocate a block of section. -- gpreadobj.c */
FUNC(gp_section_t*) gp_coffgen_make_block_section(gp_object_t *Object, unsigned Num_sections) {
gp_section_t **ptr_array;
unsigned id;
unsigned i;
if (Object->section_list.first) {
gp_error("'%s': The list of sections already exists, can not be created again.", Object->filename);
assert(0);
}
if (Num_sections == 0) {
return NULL;
}
ptr_array = (gp_section_t **)gp_list_make_block(&Object->section_list, Num_sections, sizeof(gp_section_t));
id = Object->serial_id;
for (i = 0; i < Num_sections; i++) {
ptr_array[i]->object_id = id;
ptr_array[i]->serial_id = section_serial_id++;
}
/* The first->prev and last->next values is already NULL. */
Object->section_ptr_array = ptr_array;
return Object->section_list.first;
}
/*------------------------------------------------------------------------------------------------*/
/* Add to object an exists section. */
FUNC(gp_section_t*) gp_coffgen_add_exists_section(gp_object_t *Object, gp_section_t *Section) {
if (!Object) return NULL;
gp_list_node_append(&Object->section_list, Section);
Section->object_id = Object->serial_id;
return Section;
}
/*------------------------------------------------------------------------------------------------*/
/* Behind a section inserts another section. */
FUNC(gp_section_t*) gp_coffgen_insert_after_section(gp_object_t *Object, gp_section_t *Ancestor, gp_section_t *Following) {
if (!Object) return NULL;
if (Ancestor->object_id != Object->serial_id) {
gp_error("The '%s'{%u} section does not belong to this object: '%s'{%u}",
Ancestor->name, Ancestor->object_id, Object->filename, Object->serial_id);
assert(0);
}
gp_list_node_insert_after(&Object->section_list, Ancestor, Following);
Following->object_id = Object->serial_id;
return Following;
}
/*------------------------------------------------------------------------------------------------*/
/* Add a pnew section to the object. */
FUNC(gp_section_t*) gp_coffgen_add_section(gp_object_t *Object, const char *Name, MemBlock_t *Data) {
if (!Object) return NULL;
return gp_coffgen_add_exists_section(Object, gp_coffgen_new_section(Name, Data));
}
/*------------------------------------------------------------------------------------------------*/
/* Move linked lists between two section. */
FUNC(void) gp_coffgen_transfer_section_data(gp_section_t *Receiver, gp_section_t *Sender)
{
if ((Receiver == NULL) || (Sender == NULL)) {
return;
}
gp_list_move(&Receiver->relocation_list, &Sender->relocation_list);
gp_list_move(&Receiver->line_number_list, &Sender->line_number_list);
}
/*------------------------------------------------------------------------------------------------*/
/* Update the section identifier in the all internal linked lists. */
FUNC(bool) gp_coffgen_update_all_section_id(gp_section_t *Section) {
gp_reloc_t *relocation;
gp_linenum_t *line_number;
unsigned id;
if (Section == NULL) {
return false;
}
id = Section->serial_id;
relocation = Section->relocation_list.first;
while (relocation) {
relocation->section_id = id;
relocation = relocation->next;
}
line_number = Section->line_number_list.first;
while (line_number) {
line_number->section_id = id;
line_number = line_number->next;
}
return true;
}
/*------------------------------------------------------------------------------------------------*/
/* Move all symbols of section to dead list. */
FUNC(void) gp_coffgen_move_reserve_section_symbols(gp_object_t *Object, gp_section_t *Section) {
if (!Object) return;
/* Move all symbols for the section into dead list. */
FOR (gp_symbol_list_t,it,Object->symbol_list) {
// gp_symbol_t *list = Object->symbol_list.first;
// while (list) {
// gp_symbol_t *symbol = list;
// list = list->next;
// if (symbol->section == Section) gp_coffgen_move_reserve_symbol(Object, symbol);
if (it->section == Section) gp_coffgen_move_reserve_symbol(Object, &*it);
}
}
/*------------------------------------------------------------------------------------------------*/
/* Delete all symbols of section. */
FUNC(void) gp_coffgen_del_section_symbols(gp_object_t *Object, gp_section_t *Section) {
if (!Object) return;
/* Remove all symbols for the section. */
FOR (gp_symbol_list_t,it,Object->symbol_list) {
if (it->section == Section) {
Object->gp_coffgen_del_symbol(it, true);
}
}
}
/*------------------------------------------------------------------------------------------------*/
static void _decrease_relocation_counts(gp_section_t *Section) {
gp_reloc_t *relocation;
gp_symbol_t *symbol;
gp_section_t *sym_sect;
relocation = Section->relocation_list.first;
while (relocation) {
symbol = relocation->symbol;
sym_sect = symbol->section;
if (symbol->reloc_count_all_section > 0) {
(symbol->reloc_count_all_section)--;
if (sym_sect == Section) {
/* Relocation reference from own section. */
if (symbol->reloc_count_own_section > 0) {
(symbol->reloc_count_own_section)--;
}
else {
gp_warning("Number of relocation references of symbol from own section is zero: '%s'", symbol->name);
}
}
else {
/* Relocation reference from another section. */
if (symbol->reloc_count_other_section > 0) {
(symbol->reloc_count_other_section)--;
if (sym_sect->reloc_count > 0) {
(sym_sect->reloc_count)--;
}
else {
gp_warning("Number of relocation references of section from another section is zero: '%s'", sym_sect->name);
}
}
else {
gp_warning("Number of relocation references of symbol from another section is zero: '%s'", symbol->name);
}
}
}
relocation = relocation->next;
}
}
/*------------------------------------------------------------------------------------------------*/
/* Move a section to dead list. */
FUNC(gp_section_t*) gp_coffgen_move_reserve_section(gp_object_t *Object, gp_section_t *Section) {
if (Object->section_list.first == NULL) {
return NULL;
}
if (Section->object_id != Object->serial_id) {
gp_error("The '%s'{%u} section does not belong to this object: '%s'{%u}",
Section->name, Section->object_id, Object->filename, Object->serial_id);
assert(0);
}
gp_list_node_move(&Object->dead_section_list, &Object->section_list, Section);
_decrease_relocation_counts(Section);
return Section;
}
/*------------------------------------------------------------------------------------------------*/
/* Delete a section from object. */
FUNC(bool) gp_coffgen_del_section(gp_object_t *Object, gp_section_t *Section) {
if (Object->section_list.first == NULL) {
return false;
}
if (Section->object_id != Object->serial_id) {
gp_error("The '%s'{%u} section does not belong to this object: '%s'{%u}",
Section->name, Section->object_id, Object->filename, Object->serial_id);
assert(0);
}
gp_list_node_remove(&Object->section_list, Section);
gp_coffgen_free_section(Section);
return true;
}
/*------------------------------------------------------------------------------------------------*/
static int _cdecl _section_cmp(const void *P0, const void *P1) {
const gp_section_t *s0 = *(const gp_section_t **)P0;
const gp_section_t *s1 = *(const gp_section_t **)P1;
uint32_t a0 = s0->address;
uint32_t a1 = s1->address;
if (a0 < a1) {
return -1;
}
if (a0 > a1) {
return 1;
}
return 0;
}
/*------------------------------------------------------------------------------------------------*/
/* Put in an array that sections which are located the same page. */
FUNC(gp_section_t**) gp_coffgen_make_section_array(gp_object_t *Object, unsigned *Num_sections,
unsigned Page_addr, uint32_t Flags)
{
proc_class_t pclass;
gp_section_t *section;
gp_section_t **array;
unsigned i;
unsigned page;
unsigned n_sections;
if ((Object == NULL) || (Num_sections == NULL)) {
return NULL;
}
pclass = Object->pclass;
/* Examines the sections. */
n_sections = 0;
section = Object->section_list.first;
while (section) {
FlagClr(section->opt_flags, OPT_FLAGS_GPCOFFGEN_MODULE);
page = gp_processor_page_addr(pclass, gp_processor_insn_from_byte_c(pclass, section->address));
if ((page == Page_addr) && (FlagsIsNotAllClr(section->flags, Flags))) {
/* Located on same page and there is at least one valid flag. */
++n_sections;
FlagSet(section->opt_flags, OPT_FLAGS_GPCOFFGEN_MODULE);
}
section = section->next;
}
if (n_sections == 0) {
return NULL;
}
array = new gp_section_t*[n_sections];
/* Populate the array. */
i = 0;
section = Object->section_list.first;
while (section) {
if (FlagIsSet(section->opt_flags, OPT_FLAGS_GPCOFFGEN_MODULE)) {
array[i] = section;
++i;
}
section = section->next;
}
if (n_sections > 1) {
qsort(array, n_sections, sizeof(gp_section_t *), _section_cmp);
}
*Num_sections = n_sections;
return array;
}
/*------------------------------------------------------------------------------------------------*/
/* Find by name a symbol that not section symbol. */
gp_symbol_list_t::iterator gp_object_t::gp_coffgen_find_symbol(const char *Name) {
FOR (gp_symbol_list_t,it,symbol_list) {
if (it->pclass != C_SECTION && it->name && !strcmp(it->name, Name)) {
return it;
}
}
return symbol_list.end();
}
/*------------------------------------------------------------------------------------------------*/
/* Find by name a symbol that a section symbol. */
gp_symbol_list_t::iterator gp_object_t::gp_coffgen_find_section_symbol(const char *Name) {
FOR (gp_symbol_list_t,it,symbol_list) {
if (it->pclass == C_SECTION && it->name && !strcmp(it->name, Name)) {
return it;
}
}
return symbol_list.end();
}
/*------------------------------------------------------------------------------------------------*/
/* Search for a symbol, based on the value and name of host section.
The function is slow, but only need the error messages. */
FUNC(gp_symbol_t*) gp_coffgen_find_symbol_section_value(gp_object_t *Object, const char *Section_name, long Value) {
if (!Object || !Section_name) return 0;
FOR (gp_symbol_list_t,it,Object->symbol_list) {
if (it->pclass != C_SECTION
&& it->pclass != C_FILE
&& it->section_name
&& !strcmp(it->section_name, Section_name)
&& it->value == Value) return &*it;
}
return 0;
}
/*------------------------------------------------------------------------------------------------*/
/* Allocate a block of symbols. -- gpreadobj.c */
gp_symbol_list_t::iterator gp_object_t::gp_coffgen_make_block_symbol() {
unsigned n_symbols = num_symbols;
unsigned id;
unsigned i;
if (!n_symbols) return symbol_list.end();
if (symbol_list.size()) {
gp_error("'%s': The list of symbols already exists, can not be created again.", filename);
assert(0);
}
gp_symbol_t**ptr_array = (gp_symbol_t **)gp_list_make_block(&symbol_list, n_symbols, sizeof(gp_symbol_t));
id = serial_id;
for (i = 0; i < n_symbols; i++) {
ptr_array[i]->object_id = id;
}
/* The first->prev and last->next values is already NULL. */
symbol_ptr_array = ptr_array;
return symbol_list.begin();
}
/*------------------------------------------------------------------------------------------------*/
/* Add a pnew symbol to the object. */
gp_symbol_list_t::iterator gp_object_t::gp_coffgen_add_symbol(const char *Name, int Section_number) {
/* allocate memory for the symbol */
gp_symbol_t sym;
// gp_symbol_t *pnew = (gp_symbol_t *)gp_list_node_append(&Object->symbol_list, gp_list_node_new(sizeof(gp_symbol_t)));
sym.name = GP_Strdup(Name);
sym.number = num_symbols;
sym.section_number = Section_number;
sym.object_id = serial_id;
num_symbols++;
return symbol_list.insert(symbol_list.end(),sym);
}
/*------------------------------------------------------------------------------------------------*/
/* Add a pnew auxiliary symbol to the symbol from the object. */
FUNC(gp_aux_t*) gp_coffgen_add_aux(gp_object_t *Object, gp_symbol_t *Symbol) {
gp_aux_t *pnew;
pnew = (gp_aux_t *)gp_list_node_append(&Symbol->aux_list, gp_list_node_new(sizeof(gp_aux_t)));
(Object->num_symbols)++;
return pnew;
}
/*------------------------------------------------------------------------------------------------*/
/* Allocate a block of auxiliary symbols. -- gpreadobj.c */
FUNC(gp_aux_t*) gp_coffgen_make_block_aux(gp_symbol_t *Symbol, unsigned Num_auxsyms) {
gp_aux_t **ptr_array;
#if (AUX_NONE != 0)
unsigned i;
#endif
if (Symbol->aux_list.first) {
gp_error("'%s': The list of aux symbols already exists, can not be created again.", Symbol->name);
assert(0);
}
if (Num_auxsyms == 0) {
return NULL;
}
ptr_array = (gp_aux_t **)gp_list_make_block(&Symbol->aux_list, Num_auxsyms, sizeof(gp_aux_t));
#if (AUX_NONE != 0)
for (i = 0; i < Num_auxsyms; i++) {
ptr_array[i]->type = AUX_NONE;
}
#endif
free(ptr_array);
return Symbol->aux_list.first;
}
/*------------------------------------------------------------------------------------------------*/
/* Move a symbol to dead list. */
FUNC(gp_symbol_t*) gp_coffgen_move_reserve_symbol(gp_object_t *Object, gp_symbol_t *Symbol) {
if (!Object->symbol_list.size()) return NULL;
if (Symbol->object_id != Object->serial_id) {
gp_error("The '%s'{%u} symbol does not belong to this object: '%s'{%u}",
Symbol->name, Symbol->object_id, Object->filename, Object->serial_id);
assert(0);
}
gp_list_node_move(&Object->dead_symbol_list, &Object->symbol_list, Symbol);
Object->num_symbols -= 1 + Symbol->aux_list.num_nodes;
return Symbol;
}
/*------------------------------------------------------------------------------------------------*/
/* Delete the symbol from the object. */
gp_symbol_list_t::iterator gp_object_t::gp_coffgen_del_symbol(gp_symbol_list_t::iterator it, bool Touch_number) {
unsigned n_deleted;
if (!symbol_list.size()) return symbol_list.end();
if (it->object_id != serial_id) {
gp_error("The '%s'{%u} symbol does not belong to this object: '%s'{%u}",
it->name, it->object_id, filename, serial_id);
assert(0);
}
gp_symbol_list_t::iterator ret = symbol_list.erase(it);
n_deleted = 1 + gp_coffgen_free_symbol(&*it);
if (Touch_number) num_symbols -= n_deleted;
return ret;
}
/*------------------------------------------------------------------------------------------------*/
/* Make an array from symbol list of object. */
FUNC(gp_symbol_t**) gp_coffgen_make_symbol_array(const gp_object_t *Object, int (_cdecl*Cmp)(const void *, const void *)) {
if (!Object || !Object->symbol_list.size()) return 0;
gp_symbol_t**array = new gp_symbol_t*[Object->symbol_list.size()];
unsigned i = 0;
FOR (gp_symbol_list_t,it,*const_cast<gp_symbol_list_t*>(&Object->symbol_list)) {
array[i++] = &*it;
}
assert(Object->symbol_list.size() == i);
if (Cmp && i>1) qsort(array, i, sizeof(gp_symbol_t*), Cmp);
return array;
}
/*------------------------------------------------------------------------------------------------*/
/* Convert to string the symbol type. */
FUNC(const char*) gp_coffgen_symbol_type_to_str(uint8_t Type) {
static const char * const type_str[] = {
"T_NULL",
"T_VOID",
"T_CHAR",
"T_SHORT",
"T_INT",
"T_LONG",
"T_FLOAT",
"T_DOUBLE",
"T_STRUCT",
"T_UNION",
"T_ENUM",
"T_MOE",
"T_UCHAR",
"T_USHORT",
"T_UINT",
"T_ULONG",
"T_LNGDBL",
"T_SLONG",
"T_USLONG"
};
if (Type >= ARRAY_SIZE(type_str)) {
return NULL;
}
return type_str[Type];
}
/*------------------------------------------------------------------------------------------------*/
/* Convert to string the symbol derived type. */
FUNC(const char*) gp_coffgen_symbol_derived_type_to_str(uint32_t Type) {
static const char * const type_str[] = {
"DT_NON",
"DT_PTR",
"DT_FUNCTION",
"DT_ARRAY",
"DT_ROMPTR",
"DT_FARROMPTR"
};
if (Type >= ARRAY_SIZE(type_str)) {
return NULL;
}
return type_str[Type];
}
/*------------------------------------------------------------------------------------------------*/
/* Convert to string the symbol pclass. */
FUNC(const char*) gp_coffgen_symbol_class_to_str(uint8_t Class) {
switch (Class) {
case C_NULL: return "C_NULL";
case C_AUTO: return "C_AUTO"; /* automatic variable */
case C_EXT: return "C_EXT"; /* external symbol */
case C_STAT: return "C_STAT"; /* static */
case C_REG: return "C_REG"; /* register variable */
case C_EXTDEF: return "C_EXTDEF"; /* external definition */
case C_LABEL: return "C_LABEL"; /* label */
case C_ULABEL: return "C_ULABEL"; /* undefined label */
case C_MOS: return "C_MOS"; /* member of structure */
case C_ARG: return "C_ARG"; /* function argument */
case C_STRTAG: return "C_STRTAG"; /* structure tag */
case C_MOU: return "C_MOU"; /* member of union */
case C_UNTAG: return "C_UNTAG"; /* union tag */
case C_TPDEF: return "C_TPDEF"; /* type definition */
case C_USTATIC: return "C_USTATIC"; /* undefined static */
case C_ENTAG: return "C_ENTAG"; /* enumeration tag */
case C_MOE: return "C_MOE"; /* member of enumeration */
case C_REGPARM: return "C_REGPARM"; /* register parameter */
case C_FIELD: return "C_FIELD"; /* bit field */
case C_AUTOARG: return "C_AUTOARG"; /* auto argument */
case C_LASTENT: return "C_LASTENT"; /* dummy entry (end of block) */
case C_BLOCK: return "C_BLOCK"; /* ".bb" or ".eb" */
case C_FCN: return "C_FCN"; /* ".bf" or ".ef" */
case C_EOS: return "C_EOS"; /* end of structure */
case C_FILE: return "C_FILE"; /* file name */
case C_LINE: return "C_LINE"; /* line number reformatted as symbol table entry */
case C_ALIAS: return "C_ALIAS"; /* duplicate tag */
case C_HIDDEN: return "C_HIDDEN"; /* ext symbol in dmert public lib */
case C_EOF: return "C_EOF"; /* end of file */
case C_LIST: return "C_LIST"; /* absoulte listing on or off */
case C_SECTION: return "C_SECTION"; /* section */
case C_EFCN: return "C_EFCN"; /* physical end of function */
default: return NULL;
}
}
/*------------------------------------------------------------------------------------------------*/
/* Allocate a block of relocations. -- gpreadobj.c */
FUNC(gp_reloc_t*) gp_coffgen_make_block_reloc(gp_section_t *Section, unsigned Num_relocations) {
gp_reloc_t **ptr_array;
unsigned id;
unsigned i;
if (Section->relocation_list.first) {
gp_error("'%s': The list of relocations already exists, can not be created again.", Section->name);
assert(0);
}
if (Num_relocations == 0) {
return NULL;
}
ptr_array = (gp_reloc_t **)gp_list_make_block(&Section->relocation_list, Num_relocations, sizeof(gp_reloc_t));
id = Section->serial_id;
for (i = 0; i < Num_relocations; i++) {
ptr_array[i]->section_id = id;
}
free(ptr_array);
return Section->relocation_list.first;
}
/*------------------------------------------------------------------------------------------------*/
/* Add a pnew relocation to the section. */
FUNC(gp_reloc_t*) gp_coffgen_add_reloc(gp_section_t *Section) {
gp_reloc_t *pnew;
/* allocate memory for the relocation */
pnew = (gp_reloc_t *)gp_list_node_append(&Section->relocation_list, gp_list_node_new(sizeof(gp_reloc_t)));
pnew->section_id = Section->serial_id;
return pnew;
}
/*------------------------------------------------------------------------------------------------*/
/* Clears all relocation counters. */
static void _clear_relocation_counts(const gp_object_t *Object) {
gp_section_t *section;
section = Object->section_list.first;
while (section) {
section->reloc_count = 0;
if (FlagsIsNotAllClr(section->flags, STYP_ABS | STYP_DATA)) {
/* This section get protection immediately. The additional sections' protection
is based on this. */
FlagSet(section->opt_flags, OPT_FLAGS_PROTECTED_SECTION);
}
else {
FlagClr(section->opt_flags, OPT_FLAGS_PROTECTED_SECTION);
}
section = section->next;
}
FOR(gp_symbol_list_t,it,*const_cast<gp_symbol_list_t*>(&Object->symbol_list)) {
it->reloc_count_all_section = 0;
it->reloc_count_own_section = 0;
it->reloc_count_other_section = 0;
}
}
/*------------------------------------------------------------------------------------------------*/
static bool _check_section_relocations(proc_class_t Class, gp_section_t *Section, unsigned Pass,
unsigned Behavior, unsigned Level)
{
gp_reloc_t *relocation;
gp_symbol_t *symbol;
gp_section_t *sym_sect;
bool use_counters;
bool change;
if (Level >= CHECK_RELOCATIONS_DEPTH_MAX) {
gp_warning("Depth of relocations check reached the limit: %u", CHECK_RELOCATIONS_DEPTH_MAX);
return false;
}
use_counters = (Pass == 0) ? true : false;
change = false;
relocation = Section->relocation_list.first;
while (relocation) {
symbol = relocation->symbol;
if (use_counters) {
(symbol->reloc_count_all_section)++;
}
sym_sect = symbol->section;
if (sym_sect == NULL) {
/* This is an orphan symbol. */
if (FlagIsClr(Behavior, RELOC_DISABLE_WARN)) {
if (FlagIsSet(Behavior, RELOC_ENABLE_CINIT_WARN) || (strcmp(symbol->name, "_cinit") != 0)) {
gp_warning("Relocation symbol \"%s\" [0x%0*X] has no section. (pass %u)",
symbol->name, Class->addr_digits, relocation->address, Pass);
}
}
}
else {
if (sym_sect == Section) {
/* In this case not change the level of protection. */
if (use_counters) {
(symbol->reloc_count_own_section)++;
}
}
else {
/* The symbol is located another section. */
if (use_counters) {
(symbol->reloc_count_other_section)++;
(sym_sect->reloc_count)++;
}
if (FlagIsSet(Section->opt_flags, OPT_FLAGS_PROTECTED_SECTION)) {
/* If the section of reference is s_protected, then the section of symbol also will
be s_protected. */
if (FlagIsClr(sym_sect->opt_flags, OPT_FLAGS_PROTECTED_SECTION)) {
/* Only then modify and check if have not been under protection. */
FlagSet(sym_sect->opt_flags, OPT_FLAGS_PROTECTED_SECTION);
change = _check_section_relocations(Class, sym_sect, Pass, Behavior, Level + 1);
}
}
}
}
relocation = relocation->next;
}
return change;
}
/*------------------------------------------------------------------------------------------------*/
static bool _check_object_relocations(const gp_object_t *Object, unsigned Pass, unsigned Behavior) {
proc_class_t pclass;
gp_section_t *section;
bool change;
unsigned level;
level = 0;
change = false;
pclass = Object->pclass;
section = Object->section_list.first;
while (section) {
change |= _check_section_relocations(pclass, section, Pass, Behavior, level);
section = section->next;
}
return change;
}
/*------------------------------------------------------------------------------------------------*/
/* Handle the relocation counters of sections and symbols. */
FUNC(void) gp_coffgen_check_relocations(const gp_object_t *Object, bool Enable_cinit_warns) {
unsigned pass;
_clear_relocation_counts(Object);
pass = 0;
while (true) {
/* Need for further rounds because may occur back and forth references. */
if (!_check_object_relocations(Object, pass, Enable_cinit_warns)) {
break;
}
++pass;
if (pass > CHECK_RELOCATIONS_PASS_MAX) {
gp_warning("Number of relocations check reached the limit: %u", CHECK_RELOCATIONS_PASS_MAX);
break;
}
}
}
/*------------------------------------------------------------------------------------------------*/
/* Delete the relocation from the section. */
FUNC(bool) gp_coffgen_del_reloc(gp_section_t *Section, gp_reloc_t *Relocation) {
gp_section_t *section;
gp_symbol_t *symbol;
if (Section->relocation_list.first == NULL) {
return false;
}
if (Relocation->section_id != Section->serial_id) {
gp_error("The relocation{%u} does not belong to this section: '%s'{%u}",
Relocation->section_id, Section->name, Section->serial_id);
assert(0);
}
gp_list_node_remove(&Section->relocation_list, Relocation);
symbol = Relocation->symbol;
assert(symbol);
section = symbol->section;
assert(section);
if (symbol->reloc_count_all_section > 0) {
(symbol->reloc_count_all_section)--;
if (symbol->section == Section) {
/* Relocation reference from own section. */
if (symbol->reloc_count_own_section > 0) {
(symbol->reloc_count_own_section)--;
}
else {
gp_warning("Number of relocation references of symbol from own section is zero: '%s'", symbol->name);
}
}
else {
/* Relocation reference from another section. */
if (symbol->reloc_count_other_section > 0) {
(symbol->reloc_count_other_section)--;
if (section->reloc_count > 0) {
(section->reloc_count)--;
}
else {
gp_warning("Number of relocation references of section from another section is zero: '%s'", section->name);
}
}
else {
gp_warning("Number of relocation references of symbol from another section is zero: '%s'", symbol->name);
}
}
}
else {
gp_warning("Number of relocation references of symbol from all section is zero: '%s'", symbol->name);
}
gp_list_node_free(&Section->relocation_list, Relocation);
return true;
}
/*------------------------------------------------------------------------------------------------*/
/* Convert to string the relocation type. */
FUNC(const char*) gp_coffgen_reloc_type_to_str(uint16_t Type) {
static const char * const type_str[] = {
"",
"RELOC_CALL",
"RELOC_GOTO",
"RELOC_HIGH",
"RELOC_LOW",
"RELOC_P",
"RELOC_BANKSEL",
"RELOC_PAGESEL",
"RELOC_ALL",
"RELOC_IBANKSEL",
"RELOC_F",
"RELOC_TRIS",
"RELOC_MOVLR",
"RELOC_MOVLB",
"RELOC_GOTO2/CALL2",
"RELOC_FF1",
"RELOC_FF2",
"RELOC_LFSR1",
"RELOC_LFSR2",
"RELOC_BRA/RCALL",
"RELOC_CONDBRA",
"RELOC_UPPER",
"RELOC_ACCESS",
"RELOC_PAGESEL_WREG",
"RELOC_PAGESEL_BITS",
"RELOC_SCNSZ_LOW",
"RELOC_SCNSZ_HIGH",
"RELOC_SCNSZ_UPPER",
"RELOC_SCNEND_LOW",
"RELOC_SCNEND_HIGH",
"RELOC_SCNEND_UPPER",
"RELOC_SCNEND_LFSR1",
"RELOC_SCNEND_LFSR2",
"RELOC_TRIS_3BIT",
"RELOC_PAGESEL_MOVLP"
};
if (Type >= ARRAY_SIZE(type_str)) {
Type = 0;
}
return type_str[Type];
}
/*------------------------------------------------------------------------------------------------*/
/* Allocate a block of line numbers. -- gpreadobj.c */
FUNC(gp_linenum_t*) gp_coffgen_make_block_linenum(gp_section_t *Section, unsigned Num_linenums) {
gp_linenum_t **ptr_array;
unsigned id;
unsigned i;
if (Section->line_number_list.first) {
gp_error("'%s': The list of line numbers already exists, can not be created again.", Section->name);
assert(0);
}
if (Num_linenums == 0) {
return NULL;
}
ptr_array = (gp_linenum_t **)gp_list_make_block(&Section->line_number_list, Num_linenums, sizeof(gp_linenum_t));
id = Section->serial_id;
for (i = 0; i < Num_linenums; i++) {
ptr_array[i]->section_id = id;
}
free(ptr_array);
return Section->line_number_list.first;
}
/*------------------------------------------------------------------------------------------------*/
/* Add pnew line number to the section. */
FUNC(gp_linenum_t*) gp_coffgen_add_linenum(gp_section_t *Section) {
gp_linenum_t *pnew;
/* allocate memory for the line number */
pnew = (gp_linenum_t *)gp_list_node_append(&Section->line_number_list, gp_list_node_new(sizeof(gp_linenum_t)));
pnew->section_id = Section->serial_id;
return pnew;
}
/*------------------------------------------------------------------------------------------------*/
/* Delete the line number from the section. */
FUNC(bool) gp_coffgen_del_linenum(gp_section_t *Section, gp_linenum_t *Linenum) {
if (Section->line_number_list.first == NULL) {
return false;
}
if (Linenum->section_id != Section->serial_id) {
gp_error("The line number{%u} does not belong to this section: '%s'{%u}",
Linenum->section_id, Section->name, Section->serial_id);
assert(0);
}
gp_list_node_delete(&Section->line_number_list, Linenum);
return true;
}
/*------------------------------------------------------------------------------------------------*/
/* Find line number by address in the section. */
FUNC(gp_linenum_t*) gp_coffgen_find_linenum_by_address(gp_section_t *Section, unsigned Address) {
gp_linenum_t *linenum;
if (Section->line_number_list.first == NULL) {
return NULL;
}
linenum = Section->line_number_list.first;
while (linenum) {
if (linenum->address == Address) {
return linenum;
}
linenum = linenum->next;
}
return NULL;
}
/*------------------------------------------------------------------------------------------------*/
/* Delete a line number by address from the section. */
FUNC(bool) gp_coffgen_del_linenum_by_address(gp_section_t *Section, unsigned Address) {
gp_linenum_t *linenum;
linenum = gp_coffgen_find_linenum_by_address(Section, Address);
if (linenum == NULL) {
return false;
}
return gp_coffgen_del_linenum(Section, linenum);
}
/*------------------------------------------------------------------------------------------------*/
/* Delete line numbers by address range from the section. */
FUNC(unsigned) gp_coffgen_del_linenum_by_address_area(gp_section_t *Section, unsigned Address_start,
unsigned Address_end)
{
gp_linenum_t *linenum;
gp_linenum_t *next;
unsigned num;
if (Section->line_number_list.first == NULL) {
return false;
}
num = 0;
linenum = Section->line_number_list.first;
while ((linenum) && (linenum->address <= Address_end)) {
next = linenum->next;
if (linenum->address >= Address_start) {
num += (gp_coffgen_del_linenum(Section, linenum) != false) ? 1 : 0;
}
linenum = next;
}
return num;
}
/*------------------------------------------------------------------------------------------------*/
static int _cdecl _linenum_cmp(const void *P0, const void *P1) {
const gp_linenum_t *l0 = *(const gp_linenum_t **)P0;
const gp_linenum_t *l1 = *(const gp_linenum_t **)P1;
const gp_symbol_t *sym0 = l0->symbol;
const gp_symbol_t *sym1 = l1->symbol;
unsigned num0 = l0->line_number;
unsigned num1 = l1->line_number;
if (sym0 < sym1) {
return -1;
}
if (sym0 > sym1) {
return 1;
}
if (num0 < num1) {
return -1;
}
if (num0 > num1) {
return 1;
}
return 0;
}
/*------------------------------------------------------------------------------------------------*/
/* Create line number array. Use gplink/gplink.c */
FUNC(void) gp_coffgen_make_linenum_array(gp_object_t *Object) {
gp_section_t *section;
gp_linenum_t *linenum;
gp_linenum_t **array;
unsigned n_linenums;
unsigned prev_num;
unsigned i;
section = Object->section_list.first;
while (section) {
n_linenums = section->line_number_list.num_nodes;
array = new gp_linenum_t*[n_linenums];
i = 0;
prev_num = (unsigned)(-1);
linenum = section->line_number_list.first;
while (linenum) {
/* From among identical line numbers only places the first in the array. */
if (prev_num != linenum->line_number) {
array[i] = linenum;
++i;
prev_num = linenum->line_number;
}
linenum = linenum->next;
}
/* Reduces the required memory size. */
array = (gp_linenum_t **)GP_Realloc(array, i * sizeof(gp_linenum_t *));
section->line_numbers_array = array;
section->line_numbers_array_length = i;
qsort(array, i, sizeof(gp_linenum_t *), _linenum_cmp);
section = section->next;
}
}
/*------------------------------------------------------------------------------------------------*/
/* Find a line number in array by symbol and number. Use gplink/lst.c */
FUNC(gp_linenum_t*) gp_coffgen_find_linenum(const gp_section_t *Section, const gp_symbol_t *Symbol, unsigned Line_number) {
gp_linenum_t linenum;
gp_linenum_t *ptr;
gp_linenum_t **ret;
if ((Section == NULL) || (Section->line_numbers_array == NULL)) {
return NULL;
}
linenum.symbol = Symbol;
linenum.line_number = Line_number;
ptr = &linenum;
ret = (gp_linenum_t **)bsearch(&ptr, Section->line_numbers_array, Section->line_numbers_array_length,
sizeof(gp_linenum_t *), _linenum_cmp);
return ((ret) ? *ret : NULL);
}
/*------------------------------------------------------------------------------------------------*/
/* check if the object is absolute: all sections are absolute and there
are no relocations (undefined symbols) */
FUNC(bool) gp_coffgen_is_absolute_object(const gp_object_t *Object) {
const gp_section_t *section;
section = Object->section_list.first;
while (section) {
if ((section->relocation_list.num_nodes > 0) || FlagIsClr(section->flags, STYP_ABS)) {
return false;
}
section = section->next;
}
return true;
}
/*------------------------------------------------------------------------------------------------*/
FUNC(bool) gp_coffgen_section_has_data(const gp_section_t *Section) {
if (Section->size == 0) {
return false;
}
return FlagIsSet(Section->flags, (STYP_TEXT | STYP_DATA | STYP_DATA_ROM));
}
/*------------------------------------------------------------------------------------------------*/
/* Determine if any relocation uses the symbol. */
bool gp_symbol_t::gp_coffgen_symbol_has_reloc(int Type) const{
switch (Type) {
case COFF_SYM_RELOC_OWN:
return reloc_count_own_section > 0;
case COFF_SYM_RELOC_OTHER:
return reloc_count_other_section > 0;
default:
return reloc_count_all_section > 0;
}
}
/*------------------------------------------------------------------------------------------------*/
/* Determine if the symbol is global. */
bool gp_symbol_t::gp_coffgen_is_global_symbol() const{
return pclass == C_EXT && section_number == N_SCNUM;
}
/*------------------------------------------------------------------------------------------------*/
/* Determine if the symbol is external. */
bool gp_symbol_t::gp_coffgen_is_external_symbol() const{
return pclass == C_EXT && section_number == N_UNDEF;
}
/*------------------------------------------------------------------------------------------------*/
/* Determine if the symbol is debug. */
bool gp_symbol_t::gp_coffgen_is_debug_symbol() const{
return pclass == C_NULL && section_number == N_DEBUG;
}
/*------------------------------------------------------------------------------------------------*/
/* Determine if the symbol is absolute. */
bool gp_symbol_t::gp_coffgen_is_absolute_symbol() const{
return pclass == C_NULL && section_number == N_ABS;
}
/*------------------------------------------------------------------------------------------------*/
/* Free the section. */
FUNC(void) gp_coffgen_free_section(gp_section_t *Section) {
if (Section->data) {
gp_mem_i_free(Section->data);
}
gp_list_delete(&Section->relocation_list);
gp_list_delete(&Section->line_number_list);
if (Section->line_numbers_array) {
free(Section->line_numbers_array);
}
free(Section->name);
free(Section);
}
/*------------------------------------------------------------------------------------------------*/
/* Free the symbol. */
FUNC(unsigned) gp_coffgen_free_symbol(gp_symbol_t *Symbol) {
unsigned num_auxsym;
if (!Symbol) return 0;
/* free the auxilary symbols */
num_auxsym = Symbol->aux_list.num_nodes;
if (num_auxsym > 0) {
gp_list_delete(&Symbol->aux_list);
}
if (Symbol->name) {
free(Symbol->name);
}
free(Symbol);
return num_auxsym;
}
/*------------------------------------------------------------------------------------------------*/
/* Free the object. */
FUNC(bool) gp_coffgen_free_object(gp_object_t *Object) {
if (!Object) return false;
gp_list_delete(&Object->section_list);
gp_list_delete(&Object->dead_section_list);
if (Object->section_ptr_array) delete[] Object->section_ptr_array;
gp_list_delete(&Object->symbol_list);
gp_list_delete(&Object->dead_symbol_list);
if (Object->symbol_ptr_array) delete[] Object->symbol_ptr_array;
if (Object->symbol_hashtable) delete[] Object->symbol_hashtable;
if (Object->filename) delete[] const_cast<char*>(Object->filename);
free(Object);
return true;
}
/*------------------------------------------------------------------------------------------------*/
FUNC(unsigned) gp_coffgen_determine_aux_symbol(const gp_symbol_t *Symbol) {
unsigned aux_type;
if (strcasecmp(".direct", Symbol->name) == 0) {
return AUX_DIRECT;
}
if (strcasecmp(".ident", Symbol->name) == 0) {
return AUX_IDENT;
}
if ((Symbol->derived_type & 7) == DT_FUNCTION) {
return AUX_FUNCTION;
}
switch (Symbol->pclass) {
case C_FILE:
aux_type = AUX_FILE;
break;
case C_SECTION:
aux_type = AUX_SECTION;
break;
case C_BLOCK:
case C_FCN:
aux_type = (Symbol->name[1] == 'b') ? AUX_BOBF : AUX_EOBF;
break;
default:
aux_type = AUX_NONE;
}
return aux_type;
}
Detected encoding: UTF-8 | 0
|