Rick Jenkins schrieb:
>> You have seen my assembly hack? If you put your fucntion into a separate
>> object file, it will be 100% safe, even with -o3. Without any linker
>> hacking.
>
> I have, and it's clearly the most elegant solution to my original problem. In
> particular, it confines the "trickery" to the source file containing the
> function, instead of requiring an obscure, dissociated entry in a linker
> script. After trying it out I'm convinced this is the cleanest way to go.
i'll add my thoughts here too, most of it was already said in the thread
though.
with just sections for some function you always need to ensure manually
that no function outside that segment is called and that the code is
position independent. the compiler may select to call code from libgcc
to process some things (e.g. division). this would not end up in that
section. so too many things to worry about ;-)
one solution is implement all of it in assembler. you know what you have
and can write the code in a position independent way and calculate the
size easily. a good solution if you are not afraid from the assembly.
the other possibility is to use the custom linker script. compile/link
into RAM are. then take that binary and include it as array of bytes in
the code.
i've attached a linker script to link an application to RAM and a
script that collects the code/data segments from a hex or ELF file and
outputs C code as example. the script was used by be to write
"updater-updaters" for the boot-loader approach described below. so it
is used to flash the data, but replacing that with a different startup
code should be easy.
but note that copying data to RAM and executing has to be done with
care. you probably can not return afterwards as most of your
applications variables are overwritten. the stack should be set to a
well known position so that it's not right within your newly copied
functions.
a bootstrap function for the assembler variant is provided below.
however for the second solution it needs to be rewritten slightly
differently (see comments below).
> If I felt a little less fallible, I'd use the method of a fixed, unchangeable
> reprogrammer in a non-erased section of ROM. I just have a nasty, sinking
> feeling that, the moment this was widely deployed, I'd find a bug in it...
at least it is a small peace of code with one one or two features. that
makes it easier to test and have a good feeling that there is no bug
preventing basic operation.
i do use "bootloaders" that are kept in the top 2kB Flash. i've got
firmware updates over I2C as master or as slave, BSL compatible and
others. however i did not use any encryption.
---
header file (.h):
void __attribute__((noreturn)) softBSLfromRAM(void);
assembler file (.S):
; the code between the labels "softBSL" and ".LsoftBSL_end" is copied to
; RAM and launched. put you update function between those labels. this
; snipped does not show an implementation of that.
; trick used in this solution:
; the stack pointer is used to copy the data and it will end up
; BELOW the copied code. so the code needs to leave some space in
; RAM for the stack. and the code itself should be written position
; independently. if that can not be guaranteed, better copy starting
; from 0x200 and use a separate register as counter.
.global softBSLfromRAM
.type softBSLfromRAM,@function
softBSLfromRAM:
mov #0x0400, r1 ; SP is used as dst ptr
mov #.LsoftBSL_end, r13 ; source start address
.Lcopy: decd r1 ; decrement dst pointer
decd r13 ; decrement src pointer
mov @r13, @r1 ; copy one word
cmp #softBSL, r13 ; compare with lowest src address
jne .Lcopy ; keep copying while n<len
br r1 ; execute softBSL copy in RAM
.LsoftBSLfromRAM_end:
.size softBSLfromRAM,.LsoftBSLfromRAM_end-softBSLfromRAM
/* Hacked version of the linker script of a F1121.
The .text section is moved to the RAM. The segment size is set
to 2kB, so that this file can be used to link programs for all
MSP430 derrivates. However this has the disadvantage that no
error message is shown when more that the available RAM is used
on a smaller device.
chris <[email protected]>
*/
OUTPUT_FORMAT("elf32-msp430","elf32-msp430","elf32-msp430")
OUTPUT_ARCH(msp:110)
MEMORY
{
ram (rwx) : ORIGIN = 0x0200, LENGTH = 2K
bootloader(rx): ORIGIN = 0x0c00, LENGTH = 1K
}
SECTIONS
{
/* Read-only sections, merged into text segment: */
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.text :
{
*(.rel.text)
*(.rel.text.*)
*(.rel.gnu.linkonce.t*)
}
.rela.text :
{
*(.rela.text)
*(.rela.text.*)
*(.rela.gnu.linkonce.t*)
}
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.rodata :
{
*(.rel.rodata)
*(.rel.rodata.*)
*(.rel.gnu.linkonce.r*)
}
.rela.rodata :
{
*(.rela.rodata)
*(.rela.rodata.*)
*(.rela.gnu.linkonce.r*)
}
.rel.data :
{
*(.rel.data)
*(.rel.data.*)
*(.rel.gnu.linkonce.d*)
}
.rela.data :
{
*(.rela.data)
*(.rela.data.*)
*(.rela.gnu.linkonce.d*)
}
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
/* Internal text space */
.text :
{
*(.init)
. = ALIGN(2);
*(.text)
. = ALIGN(2);
*(.text.*)
. = ALIGN(2);
*(.fini)
_etext = . ;
PROVIDE (__data_start = .) ;
. = ALIGN(2);
*(.data)
. = ALIGN(2);
*(.gnu.linkonce.d*)
. = ALIGN(2);
_edata = . ;
PROVIDE (__bss_start = .) ;
*(.bss)
*(COMMON)
PROVIDE (__bss_end = .) ;
_end = . ;
} > ram
/* bootloader */
.bootloader :
{
PROVIDE (__boot_start = .) ;
*(.bootloader)
. = ALIGN(2);
*(.bootloader.*)
} > bootloader
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
PROVIDE (__stack = 0xa00) ;
}