OS section organization

Brett Swimley brett.swimley at aedinc.net
Fri May 9 14:21:49 UTC 2003


Thanks Greg,
I'll peruse this and glean what I can from it.  I appreciate it.

Brett

Quoting gregory.menke at gsfc.nasa.gov:

> 
> Brett Swimley writes:
>  > Thanks Greg,
>  >
>  > This is exactly what I want to do, but I'm not sure about how to identify
> the
>  > desired code within my linker script.
> 
> The following is a quick brain dump from what I learned when doing
> this kind of thing.  I'm sorry about the length, but its a tricky
> issue.
> 
> 
> Some of our flight code is organized into subsystems, one per
> directory.  The linker script then assigns each subsystem its own
> chunk of ram for text, data and bss.  By making the chunk of ram
> bigger than the subsystem needs, it allows the operators to patch the
> in-memory running image on a subsystem by subsystem basis.  OTOH it
> makes for a truly byzantine script.  The upshot is if you can get all
> your app's .o files into a subdirectory beneath the directory with the
> makefile, then you can grab your .o's with a single wildcard.
> Otherwise, you may end up having to enumerate all your files in the
> script, which is a drag.  Be sure to follow your specific .o sections
> with the general wildcard sections, which will pick up all of the
> RTEMS kernel and library code, as well as anything else you've not
> allocated already.  Its possible to use regexps to control membership
> in wildcard results, but I've not pursued doing so.  There may also be
> bsp_spec issues with your bsp, but that issue, if it exists, is
> trivial to solve, so lets leave that aside.
> 
> We tend to divide text, data & bss into "userspace", then OS and then
> C library, and putting them where we choose.  In your case, I imagine
> you want to put frequently used stuff in your fast ram, which might
> conceivably end up being a combination of userspace, OS and library.
> 
> Below is an extract from a linker script I cooked up for a proof of
> concept some time ago.  Its difficult to follow, so don't read it in
> detail just yet.  There are a couple things to observe; First, in the
> MEMORY block a number of sections are defined along with their
> lengths.  I imagine you would define one section for your fast ram and
> another for regular dram.  Please note, this is only for C, you'll
> need to fancy it up a bit for C++, but that only means you'll need a
> few more magically named sections, some of which must be in particular
> sequences.  Use the RTEMS link script for your bsp as a reference.
> 
> As you can see further on in the example, several subsystems put their
> .text, .data and .bss into the section I chose for them.  Of
> particular interest is the .bootstrap section, this is where the
> bootloader is located & it must be smart enough to copy sections from
> the rom image into the right ram area.  This means symbols
> representing the eeprom and ram addresses must be defined for
> everything thats going to be copied.  The _*_rom_start and _*_rom_end
> entries correspond to the eeprom addresses, the _*_module_start and
> _*_module_end entries within the individual sections are the
> destination RAM addresses.  All of them are addressed as pointers to
> 32 bit unsigned integers;
> 
> extern unsigned32 _bootstrap_rom_start;
> 
> for example.  If you wanted to start copying the .bootstrap section
> from eprom into ram, you'd use &_bootstrap_rom_start and
> &_bootstrap_start as source and destination addresses.  They don't
> exist as symbols, as I understand it, they are immediate values that
> the linker inserts wherever referenced.  You'll also observe that only
> .text and .data sections are rigged to be copied from eeprom.  The
> other sections exist only as ranges of memory that the application is
> linked to use- though the bootloader should make sure they're cleared.
> The various _* symbols identify the addresses of those sections,
> you'll see references to them in various places within RTEMS.
> 
> The standard RTEMS bootloaders are smart enough to copy the whole
> image in one contiguous chunk of something rom-like to another
> contiguous chunk of ram, so they won't be suitable in a situation like
> this.  Therefore, you'll have to supply your own link script and a
> replacement start.S.  I found it was easiest to modify the bsp's
> start.S so it copies only the .bootstrap section into target ram, then
> jump to it in ram and it handles copying in the rest of the
> application using C, then return back into start.S and continue the
> RTEMS startup.  It is possible to use C in a very restricted manner at
> this stage of bootup, you can't call any library functions, only
> fiddle around with pointers and loops- but it sure beats writing the
> copy loops in assembly.
> 
> You don't have to modify the bsp link script and start.S, there are
> linker flags that will let you supercede the bsp versions with yours,
> that way you can cm the script and start code with the rest of your
> source- and you won't get plastered when you upgrade RTEMS later on.
> 
> There is one big proviso for this kind of thing, your app will be very
> sensitive to bugs in gcc, binutils or linker.  I've seen a number of
> occasions where something in the compiler toolchain has introduced an
> offset in the linker symbol values or emitted a few bytes of extra
> data into the image, throwing everything off.  This is extremely hard
> to to find and fix, so be sure you can easily relink with the standard
> link script.  You may also end up running to problems with link
> scripts that generate executables that look just fine (even when
> examined by objdump), but won't run.  This is sometimes due to hidden
> issues related to the order of sections, or maybe you have something
> extra or something missing.  The example below is deceptively simple.
> You shouldn't have much trouble with re-ordering .text .data or .bss
> internally, but when you start mixing them, things can get difficult.
> 
> 
> 
> ======================================================================
> 
> /* set these to .osdram so all workspace stuff will end up there */
> 
> _RamBase = DEFINED(_RamBase) ? _RamBase : 0x81500000;
> _RamSize = DEFINED(_RamSize) ? _RamSize : 1M;
> 
> HeapSize = DEFINED(HeapSize) ? HeapSize : 0x20000;
> _StackSize = DEFINED(_StackSize) ? _StackSize : 0x1000;
> ClockRate = DEFINED(ClockRate) ? ClockRate : 12000000;
> 
> 
> 
> 
> MEMORY
> {
>   /***********************************************************************/
>   /*  DRAM Memory Sections                                               */
>   /***********************************************************************/
>    .appdram           : ORIGIN = 0x80B00000, LENGTH = 0x600000  /*  6MB  */
>    .osdram            : ORIGIN = 0x81100000, LENGTH = 0x400000  /*  4MB  */
> }
> 
> 
> /* eof */
> 
> 
> 
> SECTIONS
> {
>   /*
>   ** this is kind of ugly, but it makes sure we get the the startup code
>   ** layout table and task list first in the LMA region.
>   */
>   .bootstrap : AT(_lma_target_address)
>   {
>     _bootstrap_start = .;
>     _ftext = .;
>     linkcmds/start.o(.text)
>     linkcmds/tasklib.o
>     os/taskList.o
>     os/start/rtems.o
>     . = . + 0x100;
>     _bootstrap_end = .;
>   } > .appdram
>   _bootstrap_rom_start = LOADADDR(.bootstrap);
>   _bootstrap_rom_end  = _bootstrap_rom_start + SIZEOF(.bootstrap);
> 
> 
> 
> /*
>  * If any of the task sections need to be updated, modify 'rc.template'
>  * accordingly, then run it & paste the output into this link script,
>  * replacing the contents below.  This will ensure all the tasks have a
>  * consistent layout.
>  */
> 
> 
> 
> 
> /****** BEGIN PROGRAM GENERATED LINKSCRIPT, DO NOT EDIT BELOW ******/
> 
> 
>   /***************  ci TASK  ***************/
> 
>   .text_ci ALIGN(0x8000) : AT( _bootstrap_rom_end )
>   {
>     _ci_module_start = .;
>     _ci_text_start = .;
>         _app_ram_start = .;
>     ci/*.o(.text)
>     ci/*.o(.rodata)
>     ci/*.o(.rodata1)
>     ci/*.o(.reginfo)
>     . = . + 0x100;
>     _ci_text_end = .;
>   } > .appdram
>       _app_rom_start = _bootstrap_rom_end;
>   _ci_rom_block_start = _bootstrap_rom_end;
>   _ci_rom_text_start = _ci_rom_block_start;
>   _ci_rom_text_end = _ci_rom_text_start + SIZEOF(.text_ci);
> 
>   .data_ci : AT( _ci_rom_text_end )
>   {
>     . = ALIGN(4);
>     _ci_data_start = .;
>     ci/*.o(.data)
>     . = . + 0x100;
>     _ci_data_end = .;
>   } > .appdram
>   _ci_rom_data_start = _ci_rom_text_end;
>   _ci_rom_data_end   = _ci_rom_data_start + SIZEOF(.data_ci);
> 
>   .bss_ci :
>   {
>     . = ALIGN(4);
>     _ci_bss_start = .;
>     ci/*.o(.dynbss)
>     ci/*.o(.bss)
>     ci/*.o(COMMON)
>     ci/*.o(.sbss)
>     ci/*.o(.scommon)
>     . = . + 0x400;
>     _ci_bss_end = .;
>     _ci_module_end = .;
>   } > .appdram
>   _ci_rom_bss_start = _ci_rom_data_end;
>   _ci_rom_bss_end   = _ci_rom_bss_start;
>   _ci_rom_block_end = _ci_rom_bss_end;
> 
> 
> 
> 
>   /*************************** Kernel & C library **************************/
> 
> 
>   .text : AT( _os_rom_end )
>   {
>    . = ALIGN(8);
>     _kernel_module_start = .;
>     _kernel_text_start = .;
>     *(.text)
> 
>     PROVIDE (__runtime_reloc_start = .);
>     *(.rel.sdata)
>     *(.rel.dyn)
>     PROVIDE (__runtime_reloc_stop = .);
> 
>     _kernel_text_end = .;
>   } > .osdram
>   _kernel_rom_start = _os_rom_end;
>   _kernel_rom_text_start = _kernel_rom_start;
>   _kernel_rom_text_end = _kernel_rom_text_start + SIZEOF(.text);
> 
> 
>   .ctors : AT( _kernel_rom_text_end )
>   {
>    . = ALIGN(8);
> 
>     /* gcc uses crtbegin.o to find the start of
>        the constructors, so we make sure it is
>        first.  Because this is a wildcard, it
>        doesn't matter if the user does not
>        actually link against crtbegin.o; the
>        linker won't look for a file to match a
>        wildcard.  The wildcard also means that it
>        doesn't matter which directory crtbegin.o
>        is in.  */
> 
>     KEEP (*crtbegin.o(.ctors))
> 
>     /* We don't want to include the .ctor section from
>        from the crtend.o file until after the sorted ctors.
>        The .ctor section from the crtend file contains the
>        end of ctors marker and it must be last */
> 
>     KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
>     KEEP (*(SORT(.ctors.*)))
>     KEEP (*(.ctors))
>   } >.osdram
>   _kernel_rom_ctors_start = _kernel_rom_text_end;
>   _kernel_rom_ctors_end = _kernel_rom_ctors_start + SIZEOF(.ctors);
> 
> 
>   .dtors : AT( _kernel_rom_ctors_end )
>   {
>    . = ALIGN(8);
>     KEEP (*crtbegin.o(.dtors))
>     KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
>     KEEP (*(SORT(.dtors.*)))
>     KEEP (*(.dtors))
>     etext  =  .;
>     _etext  =  .;
>   } >.osdram
>   _kernel_rom_dtors_start = _kernel_rom_ctors_end;
>   _kernel_rom_dtors_end = _kernel_rom_dtors_start + SIZEOF(.dtors);
> 
> 
> 
> 
> 
>   .rdata : AT( _kernel_rom_dtors_end )
>   {
>     _rdata = ALIGN(16);
>     *(.rdata)
>     *(.rodata)
>     *(.rodata1)
>     *(.rodata.*)
>     *(.gnu.linkonce.r*)
>   } >.osdram
>   _kernel_rom_rdata_start = _kernel_rom_dtors_end;
>   _kernel_rom_rdata_end = _kernel_rom_rdata_start + SIZEOF(.rdata);
> 
> 
>   .data : AT(_kernel_rom_rdata_end)
>   {
>     . = ALIGN(16);
>     _fdata = .;
>     *(.data)
>     *(.data.*)
>     *(.gnu.linkonce.d*)
>   } >.osdram
>   _kernel_rom_data_start = _kernel_rom_rdata_end;
>   _kernel_rom_data_end = _kernel_rom_data_start + SIZEOF(.data);
> 
> 
> 
> 
> /*
> 
> gp relative addresses are always via negative offset from the top of a
> 0x7ff0 byte long range.  There is presumably a good reason for this.
> The upshot is the start of the gp-relative section must be 16 byte
> aligned, with _gp set to a location 0x7ff0 higher in memory.  This rule
> was derived from looking at the canonical GNU MIPS linkscripts &
> objdumps of compiled code.  It might change with some upgrade to gcc.
> 
> This means _gp itself will be pointing into the middle of something
> presumably .bss, because the gp section wouldn't ordinarily be big
> enough for _gp to actually point to its top.  BUT nothing is stomped on
> because _gp offsets are always negative relative to gp's 0x7ff0 logical
> extent and gp is never used to address data which was not allocated to
> the gp relative sections.  Sheesh.
> 
> */
> 
>   . = ALIGN(16);
>   _gp = . + 0x7ff0;
> 
>   .sdata : AT(_kernel_rom_data_end)
>   {
>     *(.sdata)
>     *(.sdata)
>     *(.gnu.linkonce.s*)
>   } >.osdram
>   _kernel_rom_sdata_start = _kernel_rom_data_end;
>   _kernel_rom_sdata_end = _kernel_rom_sdata_start + SIZEOF(.sdata);
> 
> 
>   .lit8 : AT(_kernel_rom_sdata_end)
>   {
>     *(.lit8)
>   } >.osdram
>   _kernel_rom_lit8_start = _kernel_rom_sdata_end;
>   _kernel_rom_lit8_end = _kernel_rom_lit8_start + SIZEOF(.lit8);
> 
> 
>   .lit4 : AT(_kernel_rom_lit8_end)
>   {
>     *(.lit4)
>   } >.osdram
>   _kernel_rom_lit4_start = _kernel_rom_lit8_end;
>   _kernel_rom_lit4_end = _kernel_rom_lit4_start + SIZEOF(.lit4);
>   _kernel_rom_end = _kernel_rom_lit4_end;
> 
> 
> 
>   .sbss :
>   {
>    _clear_start = .;
>    edata  = .;
>    _edata  = .;
>    _fbss = .;
>    *(.sbss)
>    *(.scommon)
>   } >.osdram
> 
> 
>   .bss :
>   {
>     _bss_start = .;
>     *(.bss)
>     *(.reginfo)
>     *(COMMON)
>     _kernel_module_end = .;
>     end = .;
>     _end = .;
>   } >.osdram
> 
> 
>   .stack_heap :
>   {
>     . = ALIGN(64);
> 
>     _stack_limit = .;
>     . += _StackSize;
>     __stack = .;
>     _stack_init = .;
> 
>     HeapBase = .;
>     . += HeapSize;
> 
>     WorkspaceBase = .;
>     . += 0x100000;
>     _clear_end = .;
>   } >.osdram
> 
> ===================================================================
> 
> 
> /*
> 
> Task copy routines
> 
> 
> Note we don't include any c library calls here because the C lib isn't
> initialized yet; we're using C only as a fancy assembler at this stage.
> 
> */
> 
> 
> /*
>  * Cheat a bit & grab the declaration of the layout table...
>  */
> 
> 
> 
> extern struct romramtable taskMemLayout[];
> 
> 
> 
> /*
>  * Copy rom image to ram for the given entry of the taskMemLayout table.
>  *
>  */
> 
> int _copytask(int i, int textonly)
> {
>    unsigned int *src, *dst, *lim;
> 
>    int j = 0;
> 
>    //extern int putchar(int c);
>    //for(k=0;k<10; k++) putchar('0');
>    //putchar('\n');
> 
>    // run up thru the entry we want, make sure we don't pass the end of
>    // the table...
>    while( taskMemLayout[j].ram_module_start && j<i ) j++;
> 
>    if( taskMemLayout[j].ram_module_start )
>    {
>       // copy text
>       src = (unsigned int *)taskMemLayout[j].rom_text_start;
>       dst = (unsigned int *)taskMemLayout[j].ram_text_start;
>       lim = (unsigned int *)taskMemLayout[j].ram_text_end;
>       while( dst <= lim ){ *dst++ = *src++; }
> 
> 
>       if( !textonly )
>       {
>          // zero the bss & data
>          dst = (unsigned int *)taskMemLayout[j].ram_data_start;
>          lim = (unsigned int *)taskMemLayout[j].ram_bss_end;
>          while( dst <= lim ) { *dst++ = 0; }
> 
>          // copy data
>          src = (unsigned int *)taskMemLayout[j].rom_data_start;
>          dst = (unsigned int *)taskMemLayout[j].ram_data_start;
>          lim = (unsigned int *)taskMemLayout[j].ram_data_end;
>          while( dst <= lim ){ *dst++ = *src++; }
>       }
>    }
>    else
>       return 0;
> 
> 
>    return 1;    // success
> }
> 
> 
> 
> 
> 
> 
> /*
>  * Copy OS rom image to ram
>  *
>  */
> 
> void _copyos(void)
> {
>    extern unsigned int _os_module_start, _os_module_end;
>    extern unsigned int _os_text_start, _os_text_end, _os_data_start,
> _os_data_end;
>    extern unsigned int _os_rom_text_start, _os_rom_data_start;
> 
>    unsigned int *src, *dst, *lim;
> 
>    // zero the destination space (text, data, bss)
> 
>    dst = (unsigned int *)&_os_module_start;
>    lim = (unsigned int *)&_os_module_end;
>    while( dst <= lim ) { *dst++ = 0; }
> 
>    // copy text
>    src = (unsigned int *)&_os_rom_text_start;
>    dst = (unsigned int *)&_os_text_start;
>    lim = (unsigned int *)&_os_text_end;
>    while( dst <= lim ) { *dst++ = *src++; };
> 
>    // copy data
>    src = (unsigned int *)&_os_rom_data_start;
>    dst = (unsigned int *)&_os_data_start;
>    lim = (unsigned int *)&_os_data_end;
>    while( dst <= lim ) { *dst++ = *src++; }
> 
>    return;
> }
> 
> 
> 
> 
> 
> 
> /*
>  * Copy kernel ROM image to ram
>  *
>  */
> 
> void _copykernel(void)
> {
>    extern unsigned int _kernel_module_start, _kernel_module_end;
>    extern unsigned int _clear_start, _clear_end;
>    extern unsigned int _kernel_rom_start,_kernel_rom_end;
> 
>    unsigned int *src, *dst, *lim;
> 
>    // zero the destination space
>    dst = (unsigned int *)&_kernel_module_start;
>    lim = (unsigned int *)&_kernel_module_end;
>    while( dst <= lim ){ *dst++ = 0; }
> 
>    // zero the bss, heap & workspace
>    dst = (unsigned int *)&_clear_start;
>    lim = (unsigned int *)&_clear_end;
>    while( dst <= lim ){ *dst++ = 0; }
> 
>    // copy kernel image (note we don't use the ram address to terminate
>    // because the ram space is bloated w/ bss- ROM is only text & data
>    src = (unsigned int *)&_kernel_rom_start;
>    lim = (unsigned int *)&_kernel_rom_end;
>    dst = (unsigned int *)&_kernel_module_start;
>    while( src <= lim ){ *dst++ = *src++; }
> 
>    return;
> }
> 
> 
> /* eof */
> 
> ============================================================
> 


-- 
Brett Swimley
Advanced Electronic Designs
406-585-8892 / 406-585-8893 (fax)
brett.swimley at aedinc.net



More information about the users mailing list