/* GNU PIC coff linker functions
Copyright 2001-2005 Craig Franklin
Copyright 2016 Molnár Károly
*/
#include "stdhdr.h"
#include "libgputils.h"
bool gp_relocate_to_shared = false;
/*------------------------------------------------------------------------------------------------*/
/* Two symbol tables are constructed. The first contains the definitions of all
external symbols in all the object files. This symbol table is used for
relocation and linking. The second table contains all external symbols
that do not yet have a definition. This table is used to determine which
objects in a library are to be linked against. This table should be empty
at the begining of the relocation process. */
FUNC(void) gp_cofflink_add_symbol(symbol_table_t *Table, gp_symbol_t *Symbol, gp_object_t *File) {
/* Search the for the symbol. If not found, then add it to the global symbol table. */
symbol_t*sym = gp_sym_get_symbol(Table, Symbol->name);
if (sym) return;
sym = gp_sym_add_symbol(Table, Symbol->name);
gp_coffsymbol_t* var = new gp_coffsymbol_t;
var->symbol = Symbol;
var->file = File;
gp_sym_annotate_symbol(sym, var);
}
/*------------------------------------------------------------------------------------------------*/
FUNC(void) gp_cofflink_remove_symbol(symbol_table_t *Table, const char *Name) {
symbol_t* sym = gp_sym_get_symbol(Table, Name);
if (!sym) return;
gp_coffsymbol_t*var = (gp_coffsymbol_t*)gp_sym_get_symbol_annotation(sym);
delete var;
gp_sym_remove_symbol(Table, Name);
}
/*------------------------------------------------------------------------------------------------*/
/* Add the external symbols from an object file to the appropriate symbol
tables. NOTE: The missing symbol table is optional. This feature is
not used for generating symbol indexes for archives. */
FUNC(bool) gp_cofflink_add_symbols(symbol_table_t *Definition, symbol_table_t *Missing, gp_object_t *Object) {
if (!Definition || !Object) return false;
/* The gp_convert_file() function has read it the elements of the "object". */
FOR(gp_symbol_list_t,it,Object->symbol_list) {
/* process all external symbols that are not directives */
if (it->pclass == C_EXT && it->name[0] != '.') {
const symbol_t*sym = gp_sym_get_symbol(Definition, it->name);
if (it->section_number == N_UNDEF) {
/* This symbol is defined elsewhere. Check for it in the symbol
definitions. If it doesn't exist there, add it to the missing
symbol table, if not already entered. */
if (!sym && Missing) {
gp_cofflink_add_symbol(Missing, &*it, Object);
}
}else{
/* External symbol definition. See if it is already defined, it so
it is an error. Add the symbol to the symbol definitions and remove
it from the missing symbol table if it exists there. */
if (sym) {
/* duplicate symbol */
const gp_coffsymbol_t*var = (const gp_coffsymbol_t *)gp_sym_get_symbol_annotation(sym);
gp_error("Duplicate symbol \"%s\" defined in \"%s\" and \"%s\".",
it->name, var->file->filename, Object->filename);
}else{
gp_cofflink_add_symbol(Definition, &*it, Object);
}
if (Missing) gp_cofflink_remove_symbol(Missing, it->name);
}
}
}
return true;
}
/*------------------------------------------------------------------------------------------------*/
/* Combine all sections and symbols from all objects into one object file. */
FUNC(void) gp_cofflink_combine_objects(gp_object_t *Object) {
gp_object_t *object_list;
/* assign the time the operation occured */
Object->time = (uint32_t)time(NULL);
/* append the sections onto the list */
object_list = Object->next;
while (object_list) {
gp_coffgen_transfer_object_data(Object, object_list);
object_list = object_list->next;
}
gp_coffgen_update_all_object_id(Object);
/* FIXME: breaking the chain isn't good */
Object->next = NULL;
}
/*------------------------------------------------------------------------------------------------*/
/* Cleanup the symbol table after combining objects. */
FUNC(void) gp_cofflink_clean_table(gp_object_t *Object, symbol_table_t *Symbols) {
gp_section_t *section;
gp_reloc_t *relocation;
gp_symbol_t *symbol;
const gp_coffsymbol_t *var;
const symbol_t *sym;
// gp_symbol_t *next;
int num_clean_errors;
gp_debug("Cleaning symbol table.");
num_clean_errors = gp_real_num_errors();
/* point all relocations to the symbol definitions */
section = Object->section_list.first;
while (section) {
relocation = section->relocation_list.first;
while (relocation) {
symbol = relocation->symbol;
if (symbol->gp_coffgen_is_external_symbol()) {
/* This is an external symbol defined elsewhere. */
sym = gp_sym_get_symbol(Symbols, symbol->name);
if (sym == NULL) {
gp_error("Non-existent external symbol - \"%s\" - used in \"%s\" section.", symbol->name, section->name);
}
else {
var = (const gp_coffsymbol_t *)gp_sym_get_symbol_annotation(sym);
assert(!(var == NULL));
symbol = var->symbol;
assert(!(symbol == NULL));
relocation->symbol = symbol;
}
}
relocation = relocation->next;
}
section = section->next;
}
if (gp_real_num_errors() > num_clean_errors) {
exit(1);
}
gp_symbol_list_t::iterator it = Object->symbol_list.begin();
while (it!=Object->symbol_list.end()) {
if (it->gp_coffgen_is_external_symbol()) {
gp_debug(" removed symbol \"%s\"", it->name);
it = Object->gp_coffgen_del_symbol(it, true);
}else it++;
}
}
/*------------------------------------------------------------------------------------------------*/
/* Update the line number offsets. */
static void
_update_line_numbers(gp_linenum_t *Line_number, unsigned Offset)
{
while (Line_number) {
Line_number->address += Offset;
Line_number = Line_number->next;
}
}
/*------------------------------------------------------------------------------------------------*/
/* Combine overlay sections in an object file. */
FUNC(void) gp_cofflink_combine_overlay(gp_object_t *Object, bool Remove_symbol) {
int addr_digits;
gp_section_t *first;
gp_section_t *second;
// gp_symbol_t *symbol;
addr_digits = Object->pclass->addr_digits;
first = Object->section_list.first;
while (first) {
if (FlagIsSet(first->flags, STYP_OVERLAY)) {
second = gp_coffgen_find_section(Object, first->next, first->name);
if (second) {
/* The sections must have the same properties or they can't be combined. */
if (first->flags != second->flags) {
gp_error("Section types for \"%s\" do not match.", first->name);
continue;
}
else if (FlagIsSet(first->flags, STYP_ABS) && (first->address != second->address)) {
gp_error("Different addresses for absolute overlay sections \"%s\" (0x%0*X != 0x%0*X).",
first->name, addr_digits, first->address, addr_digits, second->address);
continue;
}
/* Set the size of the first section to the larger of the two. */
if (second->size > first->size) {
first->size = second->size;
first->symbol->aux_list.first->_aux_symbol._aux_scn.length = second->size;
}
/* Remove the section symbol. */
if (Remove_symbol) {
Object->gp_coffgen_del_symbol(second->symbol, true);
}
/* Update the symbol table */
FOR(gp_symbol_list_t,symbol,Object->symbol_list) {
if (symbol->section == second) {
symbol->section = first;
}
}
/* Remove the second section. */
gp_coffgen_del_section(Object, second);
/* Take another pass. */
gp_cofflink_combine_overlay(Object, Remove_symbol);
return;
}
}
first = first->next;
}
}
/*------------------------------------------------------------------------------------------------*/
/* Allocate memory for a stack. */
FUNC(void) gp_cofflink_make_stack(gp_object_t *Object, unsigned Num_bytes) {
gp_section_t *pnew;
unsigned i;
pnew = gp_coffgen_add_section(Object, ".stack", NULL);
pnew->flags = STYP_BSS;
pnew->size = Num_bytes;
gp_debug("Allocating stack memory of size %#x (%i).", Num_bytes, Num_bytes);
/* mark the memory locations as used */
for (i = 0; i < Num_bytes; i++) {
gp_mem_b_put(pnew->data, i, 0, ".stack", NULL);
}
/* create the symbol for the start address of the stack */
gp_symbol_list_t::iterator symbol = Object->gp_coffgen_find_symbol("_stack");
if (&*symbol && symbol->section_number > N_UNDEF) {
gp_error("The \"_stack\" symbol already exists.");
}else{
symbol = Object->gp_coffgen_add_symbol("_stack", N_SCNUM);
symbol->section = pnew;
symbol->pclass = C_EXT;
}
/* create the symbol for the end of the stack */
symbol = Object->gp_coffgen_find_symbol("_stack_end");
if (&*symbol && symbol->section_number > N_UNDEF) {
gp_error("The \"_stack_end\" symbol already exists.");
}else{
symbol = Object->gp_coffgen_add_symbol("_stack_end", N_SCNUM);
symbol->value = Num_bytes - 1;
symbol->section = pnew;
symbol->pclass = C_EXT;
}
}
/*------------------------------------------------------------------------------------------------*/
/* Merge all sections in one object file with the same name. The overlayed
sections must have been combined first. */
FUNC(void) gp_cofflink_merge_sections(gp_object_t *Object) {
int addr_digits;
gp_section_t *first;
gp_section_t *second;
// gp_symbol_t *symbol;
gp_reloc_t *relocation;
unsigned section_org;
uint8_t data;
const char *section_name;
const char *symbol_name;
unsigned last;
unsigned offset;
unsigned byte_addr;
addr_digits = Object->pclass->addr_digits;
first = Object->section_list.first;
while (first) {
second = gp_coffgen_find_section(Object, first->next, first->name);
if (second) {
/* The sections must have the same properties or they can't be combined. */
if (FlagIsSet(first->flags, STYP_ABS) ||
FlagIsSet(second->flags, STYP_ABS) ||
(strcmp(first->name, ".config") == 0) ||
(strcmp(first->name, ".idlocs") == 0)) {
gp_error("File \"%s\", section \"%s\" (0x%0*X) is absolute but occurs in more than one file.",
Object->filename, first->name, addr_digits, first->address);
exit(1);
}
gp_debug(" merging section \"%s\" with section \"%s\"", first->name, second->name);
/* Update the addresses in the relocation table. */
relocation = second->relocation_list.first;
while (relocation) {
relocation->address += first->size;
relocation = relocation->next;
}
/* Copy the section data. */
if (gp_coffgen_section_has_data(second)) {
last = second->size;
offset = first->size;
if (!gp_coffgen_section_has_data(first)) {
/* TODO optimization: adopt data from second by moving second->size bytes from org to org + offset */
first->data = gp_mem_i_create();
}
for (byte_addr = 0; byte_addr < last; byte_addr++) {
if (gp_mem_b_get(second->data, byte_addr, &data, §ion_name, &symbol_name)) {
gp_mem_b_put(first->data, byte_addr + offset, data, section_name, symbol_name);
}
else {
assert(0);
}
}
}
/* Update the line number offsets. */
_update_line_numbers(second->line_number_list.first, first->size);
if (FlagIsSet(first->flags, STYP_ROM_AREA)) {
section_org = gp_processor_insn_from_byte_c(Object->pclass, first->size);
}
else {
section_org = first->size;
}
/* Update the symbol table. */
FOR(gp_symbol_list_t,symbol,Object->symbol_list)
if (symbol->section_number > N_UNDEF && symbol->section == second) {
symbol->section = first;
symbol->value += section_org;
}
/* Add section sizes. */
first->size += second->size;
/* Append the relocations from the second section to the first. */
/* Append the line numbers from the second section to the first. */
gp_coffgen_transfer_section_data(first, second);
gp_coffgen_update_all_section_id(first);
/* Remove the second section. */
gp_coffgen_del_section(Object, second);
/* Take another pass. */
gp_cofflink_merge_sections(Object);
return;
}
first = first->next;
}
}
/*------------------------------------------------------------------------------------------------*/
/* copy data from idata section to the ROM section */
static void
_copy_rom_section(const gp_object_t *Object, const gp_section_t *Idata, gp_section_t *Rom)
{
proc_class_t pclass;
int from;
int stop;
int to;
const char *section_name;
const char *symbol_name;
uint8_t data;
uint16_t insn_retlw;
pclass = Object->pclass;
from = Idata->address;
stop = from + Idata->size;
to = Rom->address;
if (pclass->rom_width == 8) {
/* PIC16E */
for ( ; from < stop; ++from, ++to) {
if (gp_mem_b_get(Idata->data, from, &data, §ion_name, &symbol_name)) {
gp_mem_b_put(Rom->data, to, data, section_name, symbol_name);
}
}
}
else {
/* PIC12, PIC12E, PIC12I, SX, PIC14, PIC14E, PIC14EX, PIC16 */
/* select "retlw" instruction */
insn_retlw = gp_processor_retlw(pclass);
for ( ; from < stop; ++from, to += 2) {
if (gp_mem_b_get(Idata->data, from, &data, §ion_name, &symbol_name)) {
pclass->i_memory_put(Rom->data, to, insn_retlw | data, section_name, symbol_name);
}
}
}
}
/*------------------------------------------------------------------------------------------------*/
/* create the pnew section name */
static char* _create_i_section_name(const char *Name) {
size_t len = strlen(Name);
char*name_i = new char[len + 3];
memcpy(name_i, Name, len);
memcpy(name_i + len, "_i", 3);
return name_i;
}
/*------------------------------------------------------------------------------------------------*/
/* create a program memory section to hold the data */
static void _create_rom_section(gp_object_t *Object, gp_section_t *Section) {
/* create the pnew section */
char*name = _create_i_section_name(Section->name);
gp_section_t*pnew = gp_coffgen_new_section(name, NULL);
delete[] name;
if (Object->pclass->rom_width == 8) {
/* PIC16E */
pnew->size = Section->size;
/* Force the section size to be an even number of bytes. */
if (Section->size & 1) {
gp_mem_b_put(pnew->data, Section->size, 0, Object->filename, "adjust");
(pnew->size)++;
}
}else{
/* PIC12, PIC12E, PIC12I, SX, PIC14, PIC14E, PIC14EX, PIC16 */
pnew->size = Section->size << 1;
}
pnew->flags = STYP_DATA_ROM;
/* Copy the data to get the MEM_USED_MASK correct. It is copied again later
to ensure that any patched data is updated in the ROM section. */
_copy_rom_section(Object, Section, pnew);
/* Insert the pnew ROM section after the idata section. */
gp_coffgen_insert_after_section(Object, Section, pnew);
}
/*------------------------------------------------------------------------------------------------*/
/* write a word (16 bit) into four bytes of memory (non PIC16E) */
static void _write_table_u16(proc_class_t Class, const gp_section_t *Section,
unsigned Byte_address,
unsigned Insn,
unsigned Data,
const char *Symbol_name) {
Class->i_memory_put(Section->data, Byte_address, Insn | (Data & 0xff), Section->name, Symbol_name);
Class->i_memory_put(Section->data, Byte_address + 2, Insn | (Data >> 8), Section->name, Symbol_name);
}
/*------------------------------------------------------------------------------------------------*/
/* write a long (32 bit) into four bytes of memory (PIC16E) */
static void _write_table_u32(const proc_class_t Class, const gp_section_t *Section,
unsigned Byte_address,
unsigned Data,
const char *Symbol_name) {
Class->i_memory_put(Section->data, Byte_address, Data & 0xffff, Section->name, Symbol_name);
Class->i_memory_put(Section->data, Byte_address + 2, Data >> 16, Section->name, Symbol_name);
}
/*------------------------------------------------------------------------------------------------*/
/* read a word from four bytes of memory (non PIC16E) */
static uint16_t
_read_table_u16(proc_class_t Class, const gp_section_t *Section, unsigned Byte_address)
{
uint16_t data[2];
Class->i_memory_get(Section->data, Byte_address, data, NULL, NULL);
Class->i_memory_get(Section->data, Byte_address + 2, data + 1, NULL, NULL);
return ((data[0] & 0xff) | ((data[1] & 0xff) << 8));
}
/*------------------------------------------------------------------------------------------------*/
/* create the symbol for the start address of the table */
FUNC(void) gp_cofflink_make_cinit(gp_object_t *Object) {
/* create the symbol for the start address of the table */
/* TODO MPLINK 4.34 does not create this. We must implement the
section address relocations RELOC_SCN*. */
gp_symbol_list_t::iterator symbol = Object->gp_coffgen_find_symbol("_cinit");
if (&*symbol && symbol->section_number > N_UNDEF) {
gp_error("_cinit symbol already exists.");
}else{
symbol = Object->gp_coffgen_add_symbol("_cinit", N_SCNUM);
symbol->pclass = C_EXT;
}
}
/*------------------------------------------------------------------------------------------------*/
/* create ROM data for initialized data sections */
FUNC(void) gp_cofflink_make_idata(gp_object_t *Object, bool Force_cinit) {
gp_section_t *section;
proc_class_t pclass;
gp_section_t *pnew;
int count_sections;
int byte_count;
int i;
int insn_retlw;
gp_symbol_t *symbol;
count_sections = 0;
section = Object->section_list.first;
while (section) {
if (FlagIsSet(section->flags, STYP_DATA)) {
_create_rom_section(Object, section);
count_sections++;
}
section = section->next;
}
if ((count_sections > 0) || Force_cinit) {
pclass = Object->pclass;
pnew = gp_coffgen_add_section(Object, ".cinit", NULL);
pnew->flags = STYP_DATA_ROM;
byte_count = 2 + count_sections * 12;
if (pclass->rom_width != 8) {
/* PIC12, PIC12E, PIC12I, SX, PIC14, PIC14E, PIC14EX, PIC16 */
/* retlw is used so 16-bit count is stored in 4 bytes not 2 */
byte_count += 2;
}
pnew->size = byte_count;
/* load the table with data */
for (i = 0; i < byte_count; i++) {
gp_mem_b_put(pnew->data, i, 0, ".cinit", "table");
}
if (pclass->rom_width == 8) {
/* PIC16E */
pclass->i_memory_put(pnew->data, 0, count_sections, ".cinit", "table_size");
}
else {
/* PIC12, PIC12E, PIC12I, SX, PIC14, PIC14E, PIC14EX, PIC16 */
insn_retlw = gp_processor_retlw(pclass);
_write_table_u16(pclass, pnew, 0, insn_retlw, count_sections, "table_size");
}
/* update the section pointer in _cinit */
symbol = &*Object->gp_coffgen_find_symbol("_cinit");
if (!Force_cinit) {
assert(symbol);
}
if (symbol) {
symbol->section = pnew;
}
}
}
/*------------------------------------------------------------------------------------------------*/
/* load the relocated sections addresses in the table */
FUNC(void) gp_cofflink_add_cinit_section(gp_object_t *Object) {
gp_section_t *section;
proc_class_t pclass;
const gp_section_t *pnew;
const gp_section_t *prog_section;
int insn_retlw;
int count_sections;
int base_address;
char *prog_name;
uint16_t number;
pnew = gp_coffgen_find_section(Object, Object->section_list.first, ".cinit");
if (pnew) {
/* scan through the sections to determine the addresses */
count_sections = 0;
base_address = pnew->address;
pclass = Object->pclass;
if (pclass->rom_width == 8) {
/* PIC16E */
base_address += 2;
insn_retlw = 0;
}
else {
/* PIC12, PIC12E, PIC12I, SX, PIC14, PIC14E, PIC14EX, PIC16 */
base_address += 4;
insn_retlw = gp_processor_retlw(pclass);
}
section = Object->section_list.first;
while (section) {
if (FlagIsSet(section->flags, STYP_DATA)) {
/* locate the rom table */
prog_name = _create_i_section_name(section->name);
prog_section = gp_coffgen_find_section(Object, Object->section_list.first, prog_name);
free(prog_name);
if (pclass->rom_width == 8) {
/* PIC16E */
/* Write program memory address (from: source address of data in CODE space). */
_write_table_u32(pclass, pnew, base_address,
gp_processor_insn_from_byte_c(pclass, prog_section->address), "prog_mem_addr");
/* Write data memory address (to: destination address of values in DATA space). */
_write_table_u32(pclass, pnew, base_address + 4, section->address, "data_mem_addr");
/* Write the table size (size: number of bytes to copy from CODE to DATA). */
_write_table_u32(pclass, pnew, base_address + 8, section->size, "table_size");
}
else {
/* PIC12, PIC12E, PIC12I, SX, PIC14, PIC14E, PIC14EX, PIC16 */
/* Write program memory address (from: source address of data in CODE space). */
_write_table_u16(pclass, pnew, base_address, insn_retlw,
gp_processor_insn_from_byte_c(pclass, prog_section->address), "prog_mem_addr");
/* Write data memory address (to: destination address of values in DATA space). */
_write_table_u16(pclass, pnew, base_address + 4, insn_retlw, section->address, "data_mem_addr");
/* Write the table size (size: number of bytes to copy from CODE to DATA). */
_write_table_u16(pclass, pnew, base_address + 8, insn_retlw, section->size, "table_size");
}
count_sections++;
base_address += 12;
} /* if (FlagIsSet(section->flags, STYP_DATA)) */
section = section->next;
} /* while (section) */
/* make sure the section count matches */
if (pclass->rom_width == 8) {
/* PIC16E */
pclass->i_memory_get(pnew->data, pnew->address, &number, NULL, NULL);
}
else {
/* PIC12, PIC12E, PIC12I, SX, PIC14, PIC14E, PIC14EX, PIC16 */
number = _read_table_u16(pclass, pnew, pnew->address);
}
assert(number == count_sections);
}
}
/*------------------------------------------------------------------------------------------------*/
/* Set the memory used flags in a block of words. */
static void
_set_used(const gp_object_t *Object, MemBlock_t *M, unsigned Org_to_byte_shift,
unsigned Byte_address, unsigned Size, const char *Type, const char *Section_name,
bool P16e_align_needed)
{
uint8_t data;
const char *owner_section_name;
int addr_digits;
if (P16e_align_needed && (Size & 1)) {
/* code_pack --> STYP_BPACK */
gp_debug(" align to even size: %u ==> %u", Size, Size + 1);
++Size;
}
addr_digits = Object->pclass->addr_digits;
gp_debug(" marking %#x (%u) words from 0x%0*X to 0x%0*X as used", Size, Size,
addr_digits, gp_insn_from_byte(Org_to_byte_shift, Byte_address),
addr_digits, gp_insn_from_byte(Org_to_byte_shift, Byte_address + Size - 1));
for ( ; Size > 0; Byte_address++, Size--) {
if (gp_mem_b_get(M, Byte_address, &data, &owner_section_name, NULL)) {
if ((owner_section_name) && (Section_name)) {
gp_error("More %s sections use same address: 0x%0*X -- \"%s\", \"%s\"", Type,
addr_digits, gp_insn_from_byte(Org_to_byte_shift, Byte_address),
owner_section_name, Section_name);
}
else {
gp_error("More %s sections use same address: 0x%0*X", Type,
addr_digits, gp_insn_from_byte(Org_to_byte_shift, Byte_address));
}
return;
}
else {
gp_mem_b_put(M, Byte_address, 0, Section_name, NULL);
}
}
}
/*------------------------------------------------------------------------------------------------*/
/* allocate space for the absolute sections */
FUNC(void) gp_cofflink_reloc_abs(gp_object_t *Object, MemBlock_t *M,
unsigned Org_to_byte_shift, uint32_t Flags) {
gp_section_t *section;
unsigned org;
bool p16e_align_needed;
section = Object->section_list.first;
while (section) {
if (FlagIsSet(section->flags, STYP_ABS) && FlagIsSet(section->flags, Flags)) {
/* Workaround for the "odd size memory problem" in the PIC16E pclass.
code_pack --> STYP_BPACK */
p16e_align_needed = false;
if ((Object->pclass == PROC_CLASS_PIC16E) && FlagIsSet(section->flags, STYP_ROM_AREA) &&
(section->size & 1)) {
org = gp_processor_insn_from_byte_p(Object->processor, section->address);
if ((gp_processor_is_idlocs_org(Object->processor, org) < 0) &&
(gp_processor_is_config_org(Object->processor, org) < 0) &&
(gp_processor_is_eeprom_org(Object->processor, org) < 0)) {
p16e_align_needed = true;
}
}
_set_used(Object, M, Org_to_byte_shift, section->address, section->size, "absolute",
section->name, p16e_align_needed);
/* Set the relocated flag. */
FlagSet(section->flags, STYP_RELOC);
}
section = section->next;
}
}
/*------------------------------------------------------------------------------------------------*/
/* Search through all the sections in the object list. Locate the biggest
assigned section that has not been relocated. */
static gp_section_t *
_find_big_assigned(gp_section_t *Section, uint32_t Flags, symbol_table_t *Logical_sections)
{
gp_section_t *biggest;
const symbol_t *sym;
biggest = NULL;
while (Section) {
sym = gp_sym_get_symbol(Logical_sections, Section->name);
if ((sym) && FlagIsSet(Section->flags, Flags) && FlagIsClr(Section->flags, STYP_RELOC)) {
/* This section has not been relocated. */
if ((biggest == NULL) || (biggest->size < Section->size)) {
biggest = Section;
}
}
Section = Section->next;
}
return biggest;
}
/*------------------------------------------------------------------------------------------------*/
/* Search through all the sections in the object list. Locate the biggest
section that has not been relocated. */
static gp_section_t *
_find_big_section(gp_section_t *Section, uint32_t Flags)
{
gp_section_t *biggest;
biggest = NULL;
while (Section) {
if (FlagIsSet(Section->flags, Flags) && FlagIsClr(Section->flags, STYP_RELOC)) {
/* This section has not been relocated. */
if ((biggest == NULL) || (biggest->size < Section->size)) {
biggest = Section;
}
}
Section = Section->next;
}
if (biggest) {
gp_debug(" biggest section = %s, section flags = %#x, Flags = %#x",
biggest->name, biggest->flags, Flags);
}
return biggest;
}
/*------------------------------------------------------------------------------------------------*/
/* Search through the target memory. Locate the smallest block of memory
that is larger than the requested size. Return the address of that
block. */
static bool
_search_memory(const MemBlock_t *M, unsigned Org_to_byte_shift, unsigned Start,
unsigned Stop, unsigned Size, unsigned *Block_address,
unsigned *Block_size, bool Stop_at_first)
{
unsigned address;
unsigned current_address = 0;
unsigned current_size = 0;
bool mem_used;
bool in_block = false;
bool end_block = false;
bool success = false;
uint8_t byte;
/* set the size to max value */
*Block_size = (unsigned)(-1);
for (address = Start; address <= Stop; address++) {
mem_used = gp_mem_b_get(M, address, &byte, NULL, NULL);
if (address == Stop) {
if (in_block) {
/* end of the section definition */
end_block = true;
/* increment for last address */
current_size++;
}
else if (Start == Stop) {
/* special case, one word section */
if (! mem_used) {
end_block = true;
current_address = Start;
current_size = 1;
}
}
in_block = false;
}
else if (mem_used) {
if (in_block) {
/* end of an unused block of memory */
end_block = true;
}
in_block = false;
}
else {
if (! in_block) {
/* start of an unused block of memory */
gp_debug(" start unused block at %#x", gp_insn_from_byte(Org_to_byte_shift, address));
current_address = address;
current_size = 1;
}
else {
/* continuation of an unused block of memory */
current_size++;
}
in_block = true;
}
if (end_block) {
gp_debug(" end unused block at %#x with size %#x",
gp_insn_from_byte(Org_to_byte_shift, address),
gp_insn_from_byte(Org_to_byte_shift, current_size));
if (current_size >= Size) {
if (Stop_at_first) {
*Block_size = current_size;
*Block_address = current_address;
success = true;
break;
}
else if (current_size < *Block_size) {
*Block_size = current_size;
*Block_address = current_address;
success = true;
}
}
end_block = false;
}
}
return success;
}
/*------------------------------------------------------------------------------------------------*/
/* Move data in i_memory. This function assumes the move will be towards
a higher address. */
static void
_move_data(MemBlock_t *M, unsigned Byte_address, unsigned Size, unsigned New_address)
{
int org;
uint8_t data;
const char *section_name;
const char *symbol_name;
if (Byte_address == New_address) {
return;
}
gp_debug(" moving %#x (%u) bytes from %#x to %#x", Size, Size, Byte_address, New_address);
for (org = Byte_address + Size - 1; org >= 0; org--) {
gp_mem_b_assert_get(M, org, &data, §ion_name, &symbol_name);
gp_debug(" moving byte %#x from %#x to %#x", data, org, New_address + org);
gp_mem_b_put(M, New_address + org, data, section_name, symbol_name);
gp_mem_b_clear(M, org);
}
}
/*------------------------------------------------------------------------------------------------*/
/* map real addres to shadow address */
static unsigned
_map_to_shadow_address(const linker_section_t *Section_def, unsigned Address)
{
unsigned new_address;
if (Section_def->shadow_sym) {
new_address = Address + Section_def->shadow_val - Section_def->start;
gp_debug(" mapping shadow address %#x => %#x", Address, new_address);
return new_address;
}
else {
return Address;
}
}
/*------------------------------------------------------------------------------------------------*/
/* unmap real addres from shadow address */
static unsigned
_unmap_from_shadow_address(const linker_section_t *Section_def, unsigned Address)
{
unsigned new_address;
if (Section_def->shadow_sym) {
new_address = Address + Section_def->start - Section_def->shadow_val;
gp_debug(" unmapping shadow address %#x => %#x", Address, new_address);
return new_address;
}
else {
return Address;
}
}
/*------------------------------------------------------------------------------------------------*/
/* Compare function for gp_sym_clone_symbol_array(). */
static int _cdecl _sect_addr_cmp(const void *P0, const void *P1)
{
const symbol_t *sym0 = *(const symbol_t **)P0;
const symbol_t *sym1 = *(const symbol_t **)P1;
const linker_section_t *sect0 = (const linker_section_t*)gp_sym_get_symbol_annotation(sym0);
const linker_section_t *sect1 = (const linker_section_t*)gp_sym_get_symbol_annotation(sym1);
if (sect0->start < sect1->start) return -1;
if (sect0->start > sect1->start) return 1;
return 0;
}
/*------------------------------------------------------------------------------------------------*/
/* allocate memory for relocatable assigned sections */
FUNC(void) gp_cofflink_reloc_assigned(gp_object_t *Object, MemBlock_t *M, unsigned Org_to_byte_shift,
uint32_t Flags, symbol_table_t *Sections, symbol_table_t *Logical_sections) {
gp_section_t *section;
gp_section_t *current;
const symbol_t *sym;
char *section_name;
linker_section_t *section_def;
unsigned current_shadow_address;
unsigned current_size;
unsigned org;
bool p16e_align_needed;
section = Object->section_list.first;
while (true) {
current = _find_big_assigned(section, Flags, Logical_sections);
if (current == NULL) {
break;
}
/* Fetch the logical section. */
sym = gp_sym_get_symbol(Logical_sections, current->name);
assert(sym);
/* Fetch the section definition. */
section_name = (char *)gp_sym_get_symbol_annotation(sym);
sym = gp_sym_get_symbol(Sections, section_name);
assert(sym);
section_def = (linker_section_t *)gp_sym_get_symbol_annotation(sym);
assert(section_def);
p16e_align_needed = false;
/* Workaround for the "odd size memory problem" in the PIC16E pclass.
code_pack --> STYP_BPACK */
if ((Object->pclass == PROC_CLASS_PIC16E) &&
FlagIsSet(current->flags, Flags) &&
FlagIsSet(current->flags, STYP_ABS) &&
FlagIsSet(current->flags, STYP_ROM_AREA) &&
(current->size & 1)) {
org = gp_processor_insn_from_byte_p(Object->processor, current->address);
if ((gp_processor_is_idlocs_org(Object->processor, org) < 0) &&
(gp_processor_is_config_org(Object->processor, org) < 0) &&
(gp_processor_is_eeprom_org(Object->processor, org) < 0)) {
p16e_align_needed = true;
}
}
/* assign the address to this section */
if (_search_memory(M, Org_to_byte_shift,
_map_to_shadow_address(section_def, section_def->start),
_map_to_shadow_address(section_def, section_def->end),
(p16e_align_needed) ? (current->size + 1) : current->size,
¤t_shadow_address, ¤t_size, false) == 1) {
gp_debug(" logical section: '%s'", current->name);
gp_debug(" section name : '%s'", section_name);
gp_debug(" successful relocation to %#x", gp_insn_from_byte(Org_to_byte_shift, current_shadow_address));
if (gp_coffgen_section_has_data(current)) {
_move_data(current->data, current->shadow_address, current->size, current_shadow_address);
}
current->shadow_address = current_shadow_address;
current->address = _unmap_from_shadow_address(section_def, current_shadow_address);
_set_used(Object, M, 0, current_shadow_address, current->size, "relocatable assigned",
section_name, p16e_align_needed);
/* Update the line number offsets. */
_update_line_numbers(current->line_number_list.first, current->address);
/* Set the relocated flag. */
FlagSet(current->flags, STYP_RELOC);
}
else {
gp_error("No target memory available for section \"%s\".", current->name);
return;
}
}
}
/*------------------------------------------------------------------------------------------------*/
/* allocate memory for cinit section */
FUNC(void) gp_cofflink_reloc_cinit(gp_object_t *Object, MemBlock_t *M, unsigned Org_to_byte_shift, gp_section_t *Cinit_section, const symbol_table_t *Sections) {
unsigned size;
bool success;
bool type_avail;
unsigned current_shadow_address;
unsigned current_size;
unsigned smallest_shadow_address;
unsigned smallest_address;
size_t i;
const symbol_t **sym_list;
const symbol_t *sym;
size_t sym_count;
linker_section_t *section_def;
if ((Cinit_section == NULL) || FlagIsSet(Cinit_section->flags, STYP_RELOC)) {
return;
}
size = Cinit_section->size;
gp_debug(" Relocating cinit code.");
success = false;
type_avail = false;
smallest_shadow_address = (unsigned)(-1);
smallest_address = (unsigned)(-1);
sym_list = gp_sym_clone_symbol_array(Sections, _sect_addr_cmp);
/* Search the section definitions for the smallest block of memory that the section will fit in. */
sym_count = gp_sym_get_symbol_count(Sections);
for (i = 0; i < sym_count; ++i) {
sym = sym_list[i];
section_def = (linker_section_t *)gp_sym_get_symbol_annotation(sym);
if ((section_def->type == SECT_CODEPAGE) && !section_def->s_protected) {
gp_debug(" section = '%s'", Cinit_section->name);
gp_debug(" name = '%s'", gp_sym_get_symbol_name(sym));
gp_debug(" size = %#x (%u)", Cinit_section->size, Cinit_section->size);
gp_debug(" def start = %#x", section_def->start);
gp_debug(" def end = %#x", section_def->end);
if (section_def->shadow_sym) {
gp_debug(" def shadow_sym = %s", section_def->shadow_sym);
gp_debug(" def shadow_val = %#x", section_def->shadow_val);
}
type_avail = true;
if (_search_memory(M, Org_to_byte_shift,
_map_to_shadow_address(section_def, section_def->start),
_map_to_shadow_address(section_def, section_def->end),
size, ¤t_shadow_address, ¤t_size, true) == 1) {
success = true;
if (smallest_shadow_address > current_shadow_address) {
smallest_shadow_address = current_shadow_address;
smallest_address = _unmap_from_shadow_address(section_def, smallest_shadow_address);
}
}
}
}
free((void*)sym_list);
/* set the memory used flag for all words in the block */
if (success) {
gp_debug(" successful relocation to %#x", gp_insn_from_byte(Org_to_byte_shift, smallest_shadow_address));
if (gp_coffgen_section_has_data(Cinit_section)) {
_move_data(Cinit_section->data, Cinit_section->shadow_address, size, smallest_shadow_address);
}
Cinit_section->shadow_address = smallest_shadow_address;
Cinit_section->address = smallest_address;
_set_used(Object, M, 0, smallest_shadow_address, size, "cinit", Cinit_section->name, false);
/* Update the line number offsets. */
_update_line_numbers(Cinit_section->line_number_list.first, Cinit_section->address);
/* Set the relocated flag. */
FlagSet(Cinit_section->flags, STYP_RELOC);
}
else if (!type_avail) {
gp_error("Linker script has no definition that matches the type of section \"%s\".",
Cinit_section->name);
}
else {
gp_error("No target memory available for section \"%s\".", Cinit_section->name);
}
}
/*------------------------------------------------------------------------------------------------*/
/* allocate memory for relocatable unassigned sections */
FUNC(void) gp_cofflink_reloc_unassigned(
gp_object_t *Object, MemBlock_t *M, unsigned Org_to_byte_shift,
uint32_t Flags, const symbol_table_t *Sections) {
gp_section_t*section = Object->section_list.first;
while (true) {
gp_section_t*current = _find_big_section(section, Flags);
if (!current) break;
unsigned size = current->size;
bool p16e_align_needed = false;
/* determine what type of sections are being relocated */
enum section_type type;
const char*msg;
if (FlagIsSet(current->flags, STYP_ROM_AREA)) {
type = SECT_CODEPAGE;
msg = "relocating codepage";
gp_debug(" relocating code");
}else if (FlagIsSet(current->flags, STYP_ACCESS)) {
type = SECT_ACCESSBANK;
msg = "relocating accessbank";
gp_debug(" relocating accessbank");
}else if (FlagIsSet(current->flags, STYP_SHARED)) {
type = SECT_SHAREBANK;
msg = "relocating sharebank";
gp_debug(" relocating sharebank");
}else {
type = SECT_DATABANK;
msg = "relocating databank";
gp_debug(" relocating data");
}
bool first_time = true;
/* Workaround for the "odd size memory problem" in the PIC16E pclass. */
if ((Object->pclass == PROC_CLASS_PIC16E) && (type == SECT_CODEPAGE) && (size & 1)) {
unsigned org = gp_processor_insn_from_byte_p(Object->processor, current->address);
if ((gp_processor_is_idlocs_org(Object->processor, org) < 0) &&
(gp_processor_is_config_org(Object->processor, org) < 0) &&
(gp_processor_is_eeprom_org(Object->processor, org) < 0)) {
p16e_align_needed = true;
}
}
next_pass:
bool success = false;
bool type_avail = false;
unsigned smallest_shadow_address = 0;
unsigned smallest_address = 0;
unsigned smallest_size = (unsigned)(-1);
const symbol_t**sym_list = gp_sym_clone_symbol_array(Sections, _sect_addr_cmp);
/* search the section definitions for the smallest block of memory that
the section will fit in */
size_t sym_count = gp_sym_get_symbol_count(Sections);
for (size_t i = 0; i < sym_count; ++i) {
const symbol_t*sym = sym_list[i];
linker_section_t*section_def = (linker_section_t*)gp_sym_get_symbol_annotation(sym);
if ((section_def->type == type) && (!section_def->s_protected)) {
gp_debug(" section = '%s'", current->name);
gp_debug(" name = %s", gp_sym_get_symbol_name(sym));
gp_debug(" size = %#x (%u)", size, size);
gp_debug(" def start = %#x", section_def->start);
gp_debug(" def end = %#x", section_def->end);
if (section_def->shadow_sym) {
gp_debug(" def shadow_sym = %s", section_def->shadow_sym);
gp_debug(" def shadow_val = %#x", section_def->shadow_val);
}
type_avail = true;
unsigned current_shadow_address, current_size;
if (_search_memory(M, Org_to_byte_shift,
_map_to_shadow_address(section_def, section_def->start),
_map_to_shadow_address(section_def, section_def->end),
(p16e_align_needed) ? (size + 1) : size,
¤t_shadow_address, ¤t_size, false) == 1) {
success = true;
if (smallest_size > current_size) {
smallest_size = current_size;
smallest_shadow_address = current_shadow_address;
smallest_address = _unmap_from_shadow_address(section_def, smallest_shadow_address);
}
}
}
}
free((void*)sym_list);
/* set the memory used flag for all words in the block */
if (success) {
gp_debug(" successful relocation to %#x", gp_insn_from_byte(Org_to_byte_shift, smallest_shadow_address));
if (gp_coffgen_section_has_data(current)) {
_move_data(current->data, current->shadow_address, size, smallest_shadow_address);
}
current->shadow_address = smallest_shadow_address;
current->address = smallest_address;
_set_used(Object, M, 0, smallest_shadow_address, size, msg, current->name, p16e_align_needed);
/* Update the line number offsets */
_update_line_numbers(current->line_number_list.first, current->address);
/* Set the relocated flag */
FlagSet(current->flags, STYP_RELOC);
}
else if (gp_relocate_to_shared && first_time && (type == SECT_DATABANK)) {
first_time = false;
type = SECT_SHAREBANK;
gp_warning("Relocation of section \"%s\" failed, relocating to a shared memory location.", current->name);
goto next_pass;
}
else if (!type_avail) {
gp_error("Linker script has no definition that matches the type of section \"%s\".", current->name);
return;
}
else {
gp_error("No target memory available for section \"%s\".", current->name);
return;
}
}
}
/*------------------------------------------------------------------------------------------------*/
/* Update all symbols with their pnew relocated values. */
FUNC(void) gp_cofflink_update_table(gp_object_t *Object, unsigned Org_to_byte_shift) {
gp_section_t *section;
gp_section_t *sym_sect;
unsigned offset;
gp_debug("Updating symbols with their pnew relocated values.");
FOR(gp_symbol_list_t,symbol,Object->symbol_list) {
if (symbol->section_number > N_UNDEF) {
sym_sect = symbol->section;
assert(sym_sect);
if (FlagIsClr(sym_sect->flags, STYP_ABS)) {
offset = sym_sect->address;
if (FlagIsSet(sym_sect->flags, STYP_ROM_AREA)) {
offset = gp_insn_from_byte(Org_to_byte_shift, offset);
}
symbol->value += offset;
}
}
}
gp_debug("Stripping section relocated flag.");
section = Object->section_list.first;
while (section) {
FlagClr(section->flags, STYP_RELOC);
section = section->next;
}
}
/*------------------------------------------------------------------------------------------------*/
/* Create sections to fill unused memory in the pages with constant data. */
FUNC(void) gp_cofflink_fill_pages(gp_object_t *Object, MemBlock_t *M, const symbol_table_t *Sections) {
linker_section_t *section_def;
size_t i;
const symbol_t **sym_list;
const symbol_t *sym;
size_t sym_count;
bool found;
char fill_name[BUFSIZ];
unsigned fill_number;
gp_section_t *section;
unsigned current_shadow_address;
unsigned current_size;
unsigned org;
unsigned end;
gp_debug("Adding fill sections.");
sym_list = gp_sym_clone_symbol_array(Sections, _sect_addr_cmp);
/* search for any section definitions that have a fill */
sym_count = gp_sym_get_symbol_count(Sections);
fill_number = 1;
for (i = 0; i < sym_count; ++i) {
sym = sym_list[i];
section_def = (linker_section_t *)gp_sym_get_symbol_annotation(sym);
if ((section_def->type == SECT_CODEPAGE) && (section_def->use_fill)) {
while (true) {
found = _search_memory(M, Object->pclass->org_to_byte_shift,
_map_to_shadow_address(section_def, section_def->start),
_map_to_shadow_address(section_def, section_def->end),
1, ¤t_shadow_address, ¤t_size, false);
if (found) {
snprintf(fill_name, sizeof(fill_name), ".fill_%u", fill_number++);
gp_debug(" pnew section \"%s\" at %#x with size %#x and data %#x",
fill_name, current_shadow_address, current_size, section_def->fill);
section = gp_coffgen_find_section(Object, Object->section_list.first, fill_name);
if (section) {
gp_error("Fill section \"%s\" already exists.", fill_name);
free((void*)sym_list);
return;
}
else {
/* create a pnew section for the fill data */
section = gp_coffgen_add_section(Object, fill_name, NULL);
section->address = _unmap_from_shadow_address(section_def, current_shadow_address);
section->shadow_address = current_shadow_address;
section->size = current_size;
section->flags = STYP_TEXT;
/* FIXME: do we really need a section symbol? */
/* mark the memory as used */
_set_used(Object, M, Object->pclass->org_to_byte_shift,
current_shadow_address, current_size, "fill", section->name, false);
/* fill the section memory */
org = current_shadow_address;
end = org + current_size;
for ( ; org < end; org += 2) {
Object->pclass->i_memory_put(section->data, org, section_def->fill, section->name, NULL);
}
}
}
else {
break;
}
}
}
}
free((void*)sym_list);
}
/*------------------------------------------------------------------------------------------------*/
static void
_check_relative(const gp_section_t *Section, unsigned Org, int Argument, int Range)
{
/* If the branch is too far then issue a warning */
if ((Argument > Range) || (Argument < -(Range + 1))) {
gp_warning("Relative branch out of range in at %#x of section \"%s\".", Org, Section->name);
}
}
/*------------------------------------------------------------------------------------------------*/
/* patch one word with the relocated address */
static void
_patch_addr(gp_object_t *Object, gp_section_t *Section, const gp_reloc_t *Relocation,
bool Mplink_compatible)
{
proc_class_t pclass;
int num_pages;
int num_banks;
const gp_symbol_t *symbol;
int byte_addr;
int value;
uint16_t current_value;
int data;
int offset;
int bank;
int page;
bool write_data;
const insn_t *instruction;
pclass = Object->pclass;
num_pages = gp_processor_num_pages(Object->processor);
num_banks = gp_processor_num_banks(Object->processor);
symbol = Relocation->symbol;
byte_addr = Relocation->address + Section->address;
value = symbol->value + Relocation->offset;
gp_debug(" patching at %#x from %s/%s with %#x", byte_addr, Section->name, symbol->name, value);
/* fetch the current contents of the memory */
pclass->i_memory_get(Section->data, byte_addr, ¤t_value, NULL, NULL);
/* FIXME: Not sure if warnings should be generated for out of range arguments.
The linker should make sure values are within ranges in the linker scripts. */
data = 0;
write_data = true;
switch (Relocation->type) {
case RELOC_ALL:
data = value & 0xffff;
break;
case RELOC_CALL:
data = pclass->reloc_call(value);
break;
case RELOC_GOTO:
data = pclass->reloc_goto(value);
break;
case RELOC_LOW: {
instruction = pclass->find_insn(pclass, current_value);
if (instruction == NULL) {
gp_error("No instruction for %#x at %#x(%s/%s)", current_value,
byte_addr, Section->name, symbol->name);
return;
}
if (instruction->pclass == INSN_CLASS_LIT8) {
data = value & 0xff;
}
else {
data = pclass->reloc_f(value);
}
break;
}
case RELOC_HIGH:
data = pclass->reloc_high((bool)FlagIsSet(symbol->section->flags, STYP_ROM_AREA), value);
break;
case RELOC_UPPER:
data = (value >> 16) & 0xff;
break;
case RELOC_P:
data = (value << 8) & PIC16_BMSK_MOVFP;
break;
case RELOC_BANKSEL:
bank = gp_processor_bank_from_addr(pclass, value);
gp_processor_set_bank(pclass, num_banks, bank, Section->data, byte_addr, Mplink_compatible);
write_data = false;
break;
case RELOC_IBANKSEL:
bank = gp_processor_check_ibank(pclass, value);
gp_processor_set_ibank(pclass, num_banks, bank, Section->data, byte_addr);
write_data = false;
break;
case RELOC_F:
data = pclass->reloc_f(value);
break;
case RELOC_TRIS:
case RELOC_TRIS_3BIT:
data = pclass->reloc_tris(value);
break;
case RELOC_MOVLR:
data = (value << 4) & PIC16_BMSK_MOVLR;
break;
case RELOC_MOVLB:
data = pclass->reloc_movlb(value);
break;
case RELOC_GOTO2:
/* This is only used for PIC16E (pic18). */
data = (value >> 9) & PIC16E_BMSK_BRANCH_HIGHER;
break;
case RELOC_FF1:
case RELOC_FF2:
data = value & PIC16E_BMSK_MOVFF1;
break;
case RELOC_LFSR1:
data = (value >> 8) & PIC16E_BMSK_LFSR1;
break;
case RELOC_LFSR2:
data = value & PIC16E_BMSK_LFSR2;
break;
case RELOC_BRA:
data = pclass->reloc_bra(Section, value, byte_addr);
break;
case RELOC_CONDBRA: {
/* This is only used for PIC16E (pic18). */
offset = value - byte_addr - 2;
if (offset & 1) {
if (symbol->name) {
gp_warning("Destination address must be word aligned at %#x of section \"%s\" at symbol: \"%s\".",
byte_addr, Section->name, symbol->name);
}
else {
gp_warning("Destination address must be word aligned at %#x of section \"%s\".",
byte_addr, Section->name);
}
}
offset >>= 1;
_check_relative(Section, byte_addr, offset, 0x7f);
data = offset & 0xff;
break;
}
case RELOC_ACCESS:
data = (gp_processor_is_p16e_access(Object->processor, value, false)) ? 0 : 0x100;
break;
case RELOC_PAGESEL_WREG:
page = gp_processor_check_page(pclass, value);
gp_processor_set_page(pclass, num_pages, page, Section->data, byte_addr, true);
write_data = false;
break;
case RELOC_PAGESEL_BITS:
case RELOC_PAGESEL_MOVLP:
page = gp_processor_check_page(pclass, value);
gp_processor_set_page(pclass, num_pages, page, Section->data, byte_addr, false);
write_data = false;
break;
/* unimplemented relocations */
case RELOC_PAGESEL:
case RELOC_SCNSZ_LOW:
case RELOC_SCNSZ_HIGH:
case RELOC_SCNSZ_UPPER:
case RELOC_SCNEND_LOW:
case RELOC_SCNEND_HIGH:
case RELOC_SCNEND_UPPER:
case RELOC_SCNEND_LFSR1:
case RELOC_SCNEND_LFSR2:
default: {
if (symbol->name) {
gp_error("Unimplemented relocation = %s (%u) in section \"%s\" at symbol \"%s\".",
gp_coffgen_reloc_type_to_str(Relocation->type),
Relocation->type, Section->name, symbol->name);
}
else {
gp_error("Unimplemented relocation = %s (%u) in section \"%s\".",
gp_coffgen_reloc_type_to_str(Relocation->type),
Relocation->type, Section->name);
}
assert(0);
}
}
/* update memory with the pnew value */
if (write_data) {
pclass->i_memory_put(Section->data, byte_addr, current_value | data, Section->name, symbol->name);
}
}
/*------------------------------------------------------------------------------------------------*/
/* Patch all addresses with the relocated symbols. The relocations are
stripped from the sections. */
FUNC(void) gp_cofflink_patch(gp_object_t *Object, bool Mplink_compatible) {
gp_section_t *section;
const gp_reloc_t *relocation;
gp_debug("Patching data with relocated symbols.");
section = Object->section_list.first;
while (section) {
if (gp_coffgen_section_has_data(section)) {
/* patch raw data with relocation entries */
relocation = section->relocation_list.first;
while (relocation) {
_patch_addr(Object, section, relocation, Mplink_compatible);
relocation = relocation->next;
}
/* update the rom with the patched idata sections */
if (FlagIsSet(section->flags, STYP_DATA) && (section->relocation_list.first)) {
assert(FlagIsSet(section->next->flags, STYP_DATA_ROM));
_copy_rom_section(Object, section, section->next);
}
/* strip the relocations from the section */
gp_list_delete(§ion->relocation_list);
}
section = section->next;
}
}
/*------------------------------------------------------------------------------------------------*/
/* copy all executable data to pnew memory */
FUNC(MemBlock_t*) gp_cofflink_make_memory(gp_object_t *Object){
MemBlock_t *m;
const gp_section_t *section;
proc_class_t pclass;
pic_processor_t processor;
int addr_digits;
unsigned addr;
unsigned org;
unsigned stop;
const char *section_name;
const char *symbol_name;
uint8_t byte;
bool not_8_bit;
m = gp_mem_i_create();
section = Object->section_list.first;
pclass = Object->pclass;
processor = Object->processor;
addr_digits = pclass->addr_digits;
if ((pclass == PROC_CLASS_PIC12) || (pclass == PROC_CLASS_PIC12E) ||
(pclass == PROC_CLASS_PIC12I) || (pclass == PROC_CLASS_SX) ||
(pclass == PROC_CLASS_PIC14) || (pclass == PROC_CLASS_PIC14E) ||
(pclass == PROC_CLASS_PIC14EX)) {
not_8_bit = true;
}
else {
not_8_bit = false;
}
while (section) {
if (FlagIsSet(section->flags, STYP_ROM_AREA)) {
addr = section->address;
stop = addr + section->size;
gp_debug(" make memory: section \"%s\" (0x%0*X - 0x%0*X)", section->name,
addr_digits, addr, addr_digits, stop - 1);
for ( ; addr < stop; addr++) {
/* fetch the current contents of the memory */
gp_mem_b_assert_get(section->data, addr, &byte, §ion_name, &symbol_name);
if (not_8_bit) {
org = gp_processor_insn_from_byte_c(pclass, addr);
if (gp_processor_is_idlocs_org(processor, org) >= 0) {
if (addr & 1) {
/* This is higher byte. */
byte |= ((Object->processor->idlocs_mask) >> 8) & 0xFF;
}
else {
/* This is lower byte. */
byte |= Object->processor->idlocs_mask & 0xFF;
}
}
}
/* write data to pnew memory */
gp_mem_b_put(m, addr, byte, section_name, symbol_name);
}
}
section = section->next;
}
return m;
}
Vorgefundene Kodierung: UTF-8 | 0
|