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