📄 __ppc_eabi_init.c
字号:
1. The MEMORY directive now supports
addr_mode = external | internal // default is internal
addr_mode is ignored unless you have chosen the SDA PIC/PID ABI in the EPPC
Target Pref panel.
2. New directives INTERNAL_SYMBOL and EXTERNAL_SYMBOL can be used to force
the addressing of global symbols. These directives are of the
form XXXL_SYMBOL { sym1, sym2, symN } where the symbols are the link time
symbol names (mangled for c++).
The auto-generated linker defined start and end symbols for loadable
segments are internal if they are addresses into internal segments and
external if they are for external segments. All other linker defined
symbols you create in a lcf are considered external unless you redefine
them with INTERNAL_SYMBOL. The linker also defines some linker defined
symbols for its own use and they have the following default settings:
_stack_addr [top of the stack - comes from pref panel settings] external
_stack_end [bottom of the stack - comes from pref panel settings] external
_heap_addr [bottom of the heap - comes from pref panel settings] external
_heap_end [top of the heap - comes from pref panel settings] external
// the next two need to be treated as internal to be EABI compliant so
// you may not redefine them.
_SDA_BASE_ [.sdata + 0x00008000] internal
_SDA2_BASE_ [.sdata2 + 0x00008000] internal
// The previous small data pointers rely on the small data registers being
// properly initialized before being accessible. However, it is hard to
// initialize those pointers without accessing them as absolutes.
// The following two symbols are external versions of _SDA_BASE_ and
// _SDA2_BASE_ which can be used as absolutes. You may not redefine them.
_ABS_SDA_BASE_ [.sdata + 0x00008000] external
_ABS_SDA2_BASE_ [.sdata2 + 0x00008000] external
// the following are numbers, not addresses and they must be treated
// as external. You may not redefine them.
_nbfunctions [number of functions in program - deprecated] external
SIZEOF_HEADERS [size of the segment headers in a linux app] external
Especially note that the stack and heap linker generated symbols are
external. It may be more practical in a SDA PIC/PID application to
make the heap and stack be contiguous with an internal segment and
define them as internal.
*** Uses for SDA PIC/PID ***
The runtime was developed for 3 different situations:
1. All code and data segments are internal. The simplest case would be
for all segments to use the same MEMORY directive and to have all of the
bss type segments at the end. In such a simple case, the application could
be converted to a binary file and linked into another application which
could copy it to ram and jump to its entry point.
2. All of the essential segments are internal and therefore moveable but
there may be some external segments which are absolute. This situation is
probably difficult to test but you can download the entire application
to the chip and at least debug it at its link time addresses.
3. Like 2, there are internal and external segments but the application is
linked as a ROM image - the application does not need to be flashed to
ROM, however. It is possible to change the ROM Image Address to be an
address into RAM and have the debugger download the image to the RAM
address. Alternatively, you could have the ROM image converted to a bin
file and link it into another application as in 1, above. The structures
used in __init_data(), _rom_copy_info and __bss_init_info, have been
modified for SDA PIC/PID to have an extra field which tells the runtime
where the segment is internal or external so that the internal segments
will be copied to position relative addresses and the external segments
will be copied to absolute addresses.
*** Compiler/Linker support for SDA Addressing ***
You build a SDA PIC/PID application by selecting SDA PIC/PID in the ABI
popup in the EPPC Target Preference panel. When you chose that, the
compiler will define a simple that you can use to guard PIC/PID source.
#if __option(sda_pic_pid) // is true if you have chosen SDA PIC/PID ABI
If you then link, the linker will generate a table for the runtime files
__ppc_eabi_init.cpp/__ppc_eabi_init.c to use. If your application has
absolute addressing relocations (which it would by default) you will
probably get linker warnings telling you that those relocations may
cause a problem. If that happens, you have two choices. You can change
the Code Model popup in the EPPC Target Preference panel to be
SDA Based PIC/PID Addressing for all of your sources and libraries, and/or
check the Tune Relocations checkbox in the EPPC Target Preference panel.
This new option is only available for the EABI and SDA PIC/PID ABIs. For
EABI it changes 14 bit branch relocations to 24 bit branch relocations
only if they can not reach the calling site from the original relocation.
For SDA PIC/PID, it changes absolute addressed references of data from
code to use a small data register instead of r0 and changes absolute
code to code refernces to use the pc relative relocations. In general,
this will work well for normnal compiled code. It is always possible
to link in an assembly file that does not behave in a standard way.
Whether you use the Code Model SDA Based PIC/PID Addressing or not,
#pragma section has been modified to accept far_sda_rel for the data_mode
and code_mode options. If you leave those options out, the compiler
will you the Code Model to determine the appropriate modes.
Absolute Addressing defaults to data_mode = far_abs and code_mode = pc_rel.
SDA Based PIC/PID Addressing defaults to data_mode = far_sda_rel and
code_mode = pc_rel.
***************************************************************************/
/***************************************************************************/
/*
* __get_runtime_linktime_delta
*
* Assumes that r13 and r2 are initialized correctly and that they always
* stay in the same relationship to each other.
*
* Utility function to get difference between runtime and linktime addresses.
*
*/
/***************************************************************************/
static asm int __get_runtime_linktime_delta(void)
{
nofralloc
/* _ABS_SDA_BASE_, generated by the linker, is the same value as */
/* _SDA_BASE_ but forces the linker to treat it as absolutetly addressed */
/* and not to substitute r13 for r0. We therefore end up with r3 exactly */
/* as calculated at linktime. */
addis r3, r0, _ABS_SDA_BASE_@ha
addi r3, r3, _ABS_SDA_BASE_@l
/* Subtract the runtime from the linktime address. */
sub r3,r13,r3
blr
}
/***************************************************************************/
/*
* __mwerks_fixup_relocations
*
* Modify initialized pointers in the data sections to reflect correct
* runtime addresses. The linker created a table, _f_mwerks_fixup, of
* offsets into the data sections that need modification. This function
* loads the pointer at that offset and applies the runtime/linktime
* delta. We wait to call this function until after __init_data.
*
*/
/***************************************************************************/
static asm void __mwerks_fixup_relocations(void)
{
nofralloc
/* r13, r2, and r1 have their correct runtime values. */
mflr r0
/* If runtime and linktime addresses are the same, no fixup is necessary. */
bl __get_runtime_linktime_delta
cmpli cr0,r3,0
beq no_fixup
/* Initialize runtime addresses of the fixup table. _f_mwerks_fixup is the */
/* beginning of the table and _e_mwerks_fixup is the end. Note that r0 */
/* will get converted to r13 or r2 by the linker. */
addis r5,r0,_f_mwerks_fixup@ha
addis r4,r0,_e_mwerks_fixup@ha
addi r5,r5,_f_mwerks_fixup@l
addi r4,r4,_e_mwerks_fixup@l
/* Compute number of entries ((_e_mwerks_fixup - _f_mwerks_fixup) / 4). */
subf r6,r5,r4
/* If there are no entries, bail. */
cmpli cr0,r6,0
beq no_fixup
srwi r6,r6,2
mtctr r6
/* We use pre-increment, so move to first real entry - 4. */
subi r5,r5,4
fixup_loop:
/* Load address of relocation. */
lwzu r6,4(r5)
/* Update address using SDA delta. */
add r6,r6,r3
/* Load value at relocation. */
lwz r7,0(r6)
/* Update value using SDA delta. */
add r7,r7,r3
/* Store updated value. */
stw r7,0(r6)
bdnz fixup_loop
no_fixup:
mtlr r0
blr
}
/***************************************************************************/
/*
* __init_registers
*
* Initialize PowerPC EABI Registers
*
* Note: this function is guaranteed to not reference any memory; the memory
* controller may not be initialized.
*
* we now overload the function in the event that the user wants pic pid
*
*/
/***************************************************************************/
asm extern void __init_registers(void)
{
nofralloc /* see above on usage of nofralloc */
mflr r0
/* _ABS_SDA_BASE_, generated by the linker, is the same value as */
/* _SDA_BASE_ but forces the linker to treat it as absolutetly addressed */
/* and not to substitute r13 for r0. We therefore end up with r13 exactly */
/* as calculated at linktime. */
addis r13, r0, _ABS_SDA_BASE_@ha
addi r13, r13, _ABS_SDA_BASE_@l
/* _ABS_SDA2_BASE_, generated by the linker, is the same value as */
/* _SDA2_BASE_ but forces the linker to treat it as absolutetly addressed */
/* and not to substitute r2 for r0. We therefore end up with r2 exactly */
/* as calculated at linktime. */
addis r2, r0, _ABS_SDA2_BASE_@ha
addi r2, r2, _ABS_SDA2_BASE_@l
/* Grab the runtime address of __get_linktime_address. The bcl will put */
/* __get_linktime_address into LR. */
bcl 20,31,__get_linktime_address
entry __get_linktime_address
/* Move runtime address of __get_linktime_address from LR to r4. */
mflr r4
/* Grab the linktime address of __get_linktime_address. Note that r0 will */
/* get converted to r13 or r2 by the linker but because r13 and r2 may not */
/* reflect the their runtime values yet, r3 might not equal r4. */
addis r3,r0,__get_linktime_address@ha
addi r3,r3,__get_linktime_address@l
/* Subtract the runtime from the linktime address. */
sub r3,r4,r3
/* If runtime and linktime addresses are the same, no fixup is necessary. */
cmpli cr0,r3,0
beq no_fixup
/* Add the delta into small data pointers so they will reflect the current */
/* position of code and data. */
add r13,r13,r3
add r2,r2,r3
no_fixup:
/* Initialize runtime address of _stack_addr. Note that r0 will */
/* get converted to r13 or r2 by the linker if _stack_addr is */
/* treated as an internal symbol (default is external). */
addis r1, r0, _stack_addr@ha
addi r1, r1, _stack_addr@l
mtlr r0
blr
}
/***************************************************************************/
/*
* __init_data
*
* Initialize all (RAM) data sections, copying ROM sections as necessary.
*
* dst destination RAM address
* size number of bytes to zero
*
* we now overload the function in the event that the user wants pic pid
*
*/
/***************************************************************************/
extern void __init_data(void)
{
__pic_rom_copy_info *dci;
__pic_bss_init_info *bii;
int delta = __get_runtime_linktime_delta();
unsigned int size;
unsigned char *ram_addr; /* address in ram (executing address) */
unsigned char *ram_end; /* end address in ram (executing address) */
unsigned char *rom_addr; /* address in rom */
unsigned char *rom_end; /* end address in rom */
int internal;
/* for sda pic pid, if ram_end and ram_addr are swapped so that ram_end < ram_addr, */
/* then segment is internal, otherwise it is external. for eabi, addresses are external */
dci = _pic_rom_copy_info;
while (1) {
if (dci->rom_addr == 0 && dci->ram_addr == 0 && dci->ram_end == 0) break;
internal = (dci->rom_end < dci->rom_addr);
if (internal) {
rom_addr = dci->rom_end + delta;
rom_end = dci->rom_addr + delta;
} else {
rom_addr = dci->rom_addr;
rom_end = dci->rom_end;
}
internal = (dci->ram_end < dci->ram_addr);
if (internal) {
ram_addr = dci->ram_end + delta;
ram_end = dci->ram_addr + delta;
} else {
ram_addr = dci->ram_addr;
ram_end = dci->ram_end;
}
size = (unsigned int) (ram_end - ram_addr);
__copy_rom_section(ram_addr, rom_addr, size);
dci++;
}
/* Initialize with zeros: */
bii = _pic_bss_init_info;
while (1) {
if (bii->ram_addr == 0 && bii->ram_end == 0) break;
internal = (bii->ram_end < bii->ram_addr);
if (internal) {
ram_addr = bii->ram_end + delta;
ram_end = bii->ram_addr + delta;
} else {
ram_addr = bii->ram_addr;
ram_end = bii->ram_end;
}
size = (unsigned int) (ram_end - ram_addr);
__init_bss_section(ram_addr, size);
bii++;
}
/* now that data is copied to ram, we can fix up initialized pointers */
__mwerks_fixup_relocations();
}
/***************************************************************************/
/*
* __exception_info_constants
*
* Called from __init_cpp_exceptions.cpp
*
* info address of linker generated exception table info
* R2 address of variable to hold the value in r2
*
* we now overload the function in the event that the user wants pic pid
*
*/
/***************************************************************************/
extern void __exception_info_constants(void **info, char **R2)
{
register char *temp; /* r2 register contents */
asm {
mr temp,r2
}
*R2 = temp;
*info = _pic_eti_init_info;
}
/***************************************************************************/
/*
* __find_exception_addresses
*
* Called from ExceptionPPC.cp
*
* info address of linker generated exception table info
* returnaddr address within a code segment
* returnaddr address within a code segment
* ex_start address of variable to hold address of exception table info
* ex_end address of variable to hold end address of exception table info
*
* we now overload the function in the event that the user wants pic pid
*
*/
/***************************************************************************/
extern int __find_exception_addresses(void *info, char *returnaddr, void **ex_start, void **ex_end)
{
__pic_eti_init_info *eti_info = (__pic_eti_init_info*)info;
unsigned char *start; /* address */
unsigned char *end; /* end address */
int internal;
int delta = __get_runtime_linktime_delta();
while (1) {
if (eti_info->code_end - eti_info->code_start == 0) break;
internal = (eti_info->code_end < eti_info->code_start);
if (internal) {
start = eti_info->code_end + delta;
end = eti_info->code_start + delta;
} else {
start = eti_info->code_start;
end = eti_info->code_end;
}
if((unsigned char*)returnaddr>=start && (unsigned char*)returnaddr<end) {
internal = (eti_info->eti_end < eti_info->eti_start);
if (internal) {
start = eti_info->eti_end + delta;
end = eti_info->eti_start + delta;
} else {
start = eti_info->eti_start;
end = eti_info->eti_end;
}
*ex_start = start;
*ex_end = end;
return(1);
}
eti_info++;
}
return(0);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -