/* 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
|