integer variable size in bss and data segment - c

I am using a test program for understanding C memory model on linux 6.3 with kernal version 2.6.32-279.el6.x86_64 .
First i have compile below code,
#include <stdio.h>
int main(void)
{
static int i = 100; /* Initialized static variable stored in DS*/
return 0;
}
on running size command , i got below ,
[root#rachitjain jan14]# size a.out
text data bss dec hex filename
1040 488 16 1544 608 a.out
then, after removing the intialization for static variable 'i' , my code becomes ,
include <stdio.h>
int main(void)
{
static int i ;
return 0;
}
On running size on after compiling above ,
[root#rachitjain jan14]# size a.out
text data bss dec hex filename
1040 484 24 1548 60c a.out
There is 8 byte increment in bss section but only 4 bytes are reduced in the data section. Why the size is integer in getting doubled while moving to bss segment ?
I have tested this character and float as well , observed the same behavioral.

Look, the answer is that the .bss section has a requirement to be aligned on 64 bits and the .data does not have this requirement.
How can you see this? When you build your program ld uses a default linker script in order to build your program. You can see it if you add -Wl,-verbose:
g++ main.cpp -Wl,-verbose
When you build 64 bit applicaton this is a default aligment for .bss section:
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
As you can see ALIGN(. != 0 ? 64 / 8 : 1); tells to align to 8 bytes
When you build 32 bit applicaton (g++ -m32 main.cpp -Wl,-verbose) this is a default aligment for .bss section:
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
Your .data section obviously does not have any ALIGN commands in the default linker script:
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
Useful links:
http://sourceware.org/ml/binutils/2009-05/msg00174.html
http://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/expressions.html)
http://lwn.net/Articles/531148/
ALIGN in Linker Scripts

Related

GCC LD NOLOAD linker section generates loadable segment

I'm working on an Arm bare-metal application and I've marked some sections with NOLOAD. According to the explanation in Understanding linker script NOLOAD sections in embedded software
, I expected the resulting ELF file to not have a loadable segment (program header) for these sections, but it does.
Is this correct? Why are those sections marked as loadable in the ELF file?
As the linker is still placing the data in .bss, how a loader is supposed to know that the sections shouldn't be loaded? Or am I missing the meaning of 'load' in the sense that NOLOAD only makes sense for initialized symbols (which would normally be placed into .data)?
This is a part of my linker script:
.bss (NOLOAD) :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss_begin .bss_begin.*)
*(.bss .bss.*)
*(COMMON)
*(.bss_end .bss_end.*)
. = ALIGN(4);
__bss_end__ = .;
} >DRAM
.noinit (NOLOAD) :
{
. = ALIGN(4);
__noinit_start__ = .;
*(.noinit .noinit.*)
. = ALIGN(4) ;
__noinit_end__ = .;
} > DRAM
/* Check if there is enough space to allocate the main stack */
._stack (NOLOAD) :
{
. = ALIGN(4);
. = . + __Main_Stack_Size ;
. = ALIGN(4);
} >DRAM
This is the output ELF file:
arm-none-eabi-readelf.exe -l test.elf
Elf file type is EXEC (Executable file)
Entry point 0x601b9
There are 2 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0x00060000 0x00060000 0x06840 0x06840 RWE 0x10000
LOAD 0x020000 0x20010000 0x20010000 0x00000 0x06084 RW 0x10000
Section to Segment mapping:
Segment Sections...
00 .text .ARM.exidx.reset .data
01 .systemclock .bss ._stack
Why are the .bss and ._stack sections there?
Thanks!!
The FileSiz of the second segment is 0 which means that there is no data that will be loaded from the elf file into this segment.
The reason why this segment exists in the table is that on a non-embedded system, the program loader would still need to request memory for sections in that segment and mark the relevant pages with the relevant attributes (readable and writable in this case).
Edit: After reading the question again, I did a bit more experimenting and it seems that all (NOLOAD) seems to do is to set the type of the section in the output file to SHT_NOBITS. The elf specification calls that a section that occupies no space in the file but is still part of the program's memory image.
If the goal is to link against code that is already present in the rom before the program is loaded, those symbols should be defined in the linker script outside of any section. E.g. already_present_code = 0x06000000; SECTIONS { .text : {*(.text*)} /* ... */}. That seems to have the desired effect.

Why different size of memory gets allocated to integer in BSS and in Data segment? [duplicate]

This question already has an answer here:
Why the int type takes up 8 bytes in BSS section but 4 bytes in DATA section
(1 answer)
Closed 5 years ago.
Please go through the following program -
#include <stdio.h>
void main()
{
}
Memory allocated for each segment is as follows(by using size command on Unix)-
text data bss dec hex filename
1040 484 16 1540 604 try
After declaration of global variable-
#include <stdio.h>
int i;
void main()
{
}
Memory allocated for each segment is as follows(by using size command on Unix)
Here variable 'i' has received memory in BSS(previously it was 16 and now it is 24)-
text data bss dec hex filename
1040 484 24 1548 60c try
After declaration of global variable and initializing it with 10-
#include <stdio.h>
int i=10;
void main()
{
}
Memory allocated for each segment is as follows(by using size command on Unix)
Here variable 'i' has received memory in data segment(previously it was 484 and now it is 488)-
text data bss dec hex filename
1040 488 16 1544 608 try
My question is why the global variable 'i' got the memory of size 8 bytes when it was stored in BSS but got 4 bytes when it was stored in data segment?
Why there is the difference in allocating memory to an integer in BSS and data segment?
why the global variable 'i' got the memory of size 8 bytes when it was stored in BSS but got 4 bytes when it was stored in data segment?
First, why 4 bytes in data segment?
As many folks already answered this - The .data segment contains any global or static variables that are initialized beforehand. An integer is of 4 bytes in size and that is reflecting in data segment size when you have global int i=10; in your program.
Now, why 8 bytes in .bss segment?
You are observing this behavior because of the default linker script of GNU linker GNU ld. You can get information about linker script here.
While linking, GNU linker (GNU ld) is using the default linker script.
The default linker script specifies the alignment for .bss segment.
If you want to see the default linker script, you can do it using command -
gcc -Wl,-verbose main.c
The output of this gcc command will contain following statement:
using internal linker script:
==================================================
// The content between these two lines is the default linker script
==================================================
In the default linker script, you can find the .bss section:
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
Here, you can see . = ALIGN(. != 0 ? 64 / 8 : 1); which indicates the default alignment as 8 bytes.
The program:
#include <stdio.h>
int i;
void main()
{
}
when built with default linker script, 'i' get the memory of size 8 bytes in BSS because of 8 bytes alignment:
# size a.out
text data bss dec hex filename
1040 484 24 1548 60c a.out
[bss = 24 bytes (16 + 8)]
GNU linker provides a provision to pass your own linker script to it and in that case, it uses the script passed to it to build the target instead of default linker script.
Just to try this, you can copy the content of default linker script in a file and use this command to pass your linker script to GNU ld:
gcc -Xlinker -T my_linker_script main.c
Since you can have your own linker script, so you can make changes in it and see the change in behavior.
In the .bss section, change this . = ALIGN(. != 0 ? 64 / 8 : 1); to . = ALIGN(. != 0 ? 32 / 8 : 1);. This will change the default alignment from 8 bytes to 4 bytes. Now build your target using linker script with this change.
The output is:
# size a.out
text data bss dec hex filename
1040 484 20 1544 608 a.out
Here you can see bss size is 20 bytes (16 + 4) because of 4 bytes alignment.
Hope this answer your question.

Why does objcopy exclude one section but not another?

Background
I'm attempting to utilize a special section of SRAM on my STM32 device which is located at address 0x40006000. One way of doing this which I saw in ST's example code was just to simply create pointers whose value happened to live inside that section of RAM. What I'm trying to do is get the linker to manage static allocations in that section for me.
Basically, I'm going from something like this:
static uint16_t *buffer0 = ((uint16_t *)0x40006000);
static uint16_t *buffer1 = ((uint16_t *)0x40006080);
To something like this (which I think is far less breakable and not as hacky, though not as portable):
#define _PMA __attribute__((section(".pma"), aligned(2)))
static uint16_t _PMA buffer0[64];
static uint16_t _PMA buffer1[64];
In order to accomplish this, I've modified my linker script to have a new memory called "PMA" located at 0x40006000 and I have located the ".pma" section inside it as follows:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
PMA (xrw) : ORIGIN = 0x40006000, LENGTH = 1024 /* This is the memory I added */
}
SECTIONS
{
.text
{
..blah blah blah..
} > FLASH
...more sections, like rodata and init_array..
/* Initialized data goes into RAM, load LMA copy after code */
.data
{
..blah blah blah with some linker symbols to denote the start and end..
} >RAM AT> FLASH
.bss
{
..blah blah blah..
} >RAM
.pma /* My new section! */
{
_pma_start = .;
. = ALIGN(2);
*(.pma)
*(.pma*)
} >PMA
}
What Happens
So this seems all fine and dandy, my stuff compiles and the map shows me that buffer0 and buffer1 are indeed placed at 0x40006000 and 0x40006080. Here is the output of the last bit of my makefile:
arm-none-eabi-gcc obj/usb_desc.o obj/usb_application.o obj/osc.o obj/usb.o obj/main.o obj/system_stm32f1xx.o obj/queue.o obj/list.o obj/heap_1.o obj/port.o obj/tasks.o obj/timers.o obj/startup_stm32f103x6.o -TSTM32F103X8_FLASH.ld -mthumb -mcpu=cortex-m3 --specs=nosys.specs -Wl,-Map,bin/blink.map -o bin/blink.elf
arm-none-eabi-objdump -D bin/blink.elf > bin/blink.lst
arm-none-eabi-size --format=SysV bin/blink.elf
bin/blink.elf :
section size addr
.isr_vector 268 134217728
.text 13504 134218000
.rodata 44 134231504
.ARM 8 134231548
.init_array 8 134231556
.fini_array 4 134231564
.data 1264 536870912
.jcr 4 536872176
.bss 1348 536872180
._user_heap_stack 1536 536873528
.pma 256 1073766400
.ARM.attributes 41 0
.debug_info 26748 0
.debug_abbrev 5331 0
.debug_aranges 368 0
.debug_line 5274 0
.debug_str 8123 0
.comment 29 0
.debug_frame 4988 0
Total 69146
arm-none-eabi-objcopy -R .stack -O binary bin/blink.elf bin/blink.bin
I see that .pma has 256 bytes used, just as I expected. The address looks correct as well. Now, when I ls the bin directory I'm greeted by this:
-rwxr-xr-x 1 kevin users 939548800 Nov 2 00:04 blink.bin*
-rwxr-xr-x 1 kevin users 221528 Nov 2 00:04 blink.elf*
That bin file is what I'm loading onto my chip's flash via openocd. It is an image of the flash starting at 0x08000000.
Sidenote: I actually attempted to load that bin file onto my chip before I had realized how huge it was...that didn't work obviously.
Here's what I get when I remove the PMA section:
arm-none-eabi-size --format=SysV bin/blink.elf
bin/blink.elf :
section size addr
.isr_vector 268 134217728
.text 13504 134218000
.rodata 44 134231504
.ARM 8 134231548
.init_array 8 134231556
.fini_array 4 134231564
.data 1392 536870912
.jcr 4 536872304
.bss 1348 536872308
._user_heap_stack 1536 536873656
.ARM.attributes 41 0
.debug_info 26748 0
.debug_abbrev 5331 0
.debug_aranges 368 0
.debug_line 5274 0
.debug_str 8123 0
.comment 29 0
.debug_frame 4988 0
Total 69018
And the file size is exactly as I would expect:
-rwxr-xr-x 1 kevin users 15236 Nov 2 00:09 blink.bin
-rwxr-xr-x 1 kevin users 198132 Nov 2 00:09 blink.elf
Question
As I understand it, what is going on here is that objcopy has just copied everything from 0x08000000 to 0x400060FF into that bin file. That is obviously not what I wanted to happen. I expected that it would just copy the flash.
Now, obviously I can just say -R .pma on my objcopy command and everything will be happy. However, what I'm curious about is how objcopy knows not to copy .data into the binary image. I noticed that running objcopy -R .data has the exact same result as running objcopy without that. Same thing with .bss. This tells me that it isn't the AT command in the linker script (which is the only real difference I can see between .data and .bss)
What can I do to make my .pma section behave the same way as .data or .bss from objcopy's perspective? Is there something interesting going on with .data/.bss in the intermediate elf file I'm using perhaps (see above for the linker command generating the elf file)?
Having defined your section as ".pma" most probably gave it the type "PROGBITS" (check with readelf), which indicates a section to be loaded on the target.
What you want/need is to define a section that doesn't have to be loaded on the target, like the ".bss" section, which has the type "NOBITS".
I frequently use the following section definition to avoid having certain buffers into the ".bss" section (as this slows down the startup phase due to the zero-initalization of the ".bss" section):
static uint8_t uart1_buffer_rx[4096] __attribute__((section(".noinit,\"aw\",%nobits#")));
I don't remember why I used the name ".noinit", but this sections appears after the ".bss" section.
In your case, it will probably help to add the "aw" and "nobits" flags after the ".pma" section declaration.

How to get the first address of initialized data segment

my program is working on linux using gcc. Through the manual page, I find edata, which represent the first address past the end of the initialized data segment.
But I want know the first address of initialized data segment
How can I get it?
I have tried treating etext as the first address of initialized data segment. Then I got a segment fault when I increase the address and access the variable stored in it. I think some address space between etext and edata was not mapped into virtual memory. Is that right?
That depends on your linker scripts. For example on some platforms you have the symbol __bss_start at the beginning of BSS. It's a symbol without any data associated with it, you can get a pointer to it by extern declaring a variable with that name (only for the sake of taking the address of that variable). For example:
#include <stdio.h>
extern char __bss_start;
int main()
{
printf("%p\n", &__bss_start);
return 0;
}
You find this by looking in the linker script, for example in /usr/lib/ldscripts/elf_x64_64.x:
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
__bss_start = .; /* <<<<< this is what you're looking for /*
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
You can also see the edata you mentioned, but as edata is not reserved for the implementation (the PROVIDE means only to create this symbol if it otherwise isn't used) you should probably use _edata instead.
If you want the address to the start of the data section you could modify the linker script:
__data_start = . ;
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
__bss_start = .; /* <<<<< this is what you're looking for /*
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
You probably want to make a copy of the linker script (look for the right one in /usr/lib/ldscripts, they are different depending on what kind of output you're targeting) and supply it when you compile:
gcc -o execfile source.c -Wl,-T ldscript
Another option if you don't want to modify the linker script could be to use the __executable_start and parse the ELF headers (hoping that the executable is sufficiently linearly mapped)
As for _etext, it is the end of the text section (you can read that in the linker script as well, but I didn't include it in the excerpt), but the text section is followed by rodata, trying to write there is probably going to segfault.
You can use the linux tool size (binutils package in Debian/Ubuntu).
Example
size -A /usr/bin/gcc
results in
/usr/bin/gcc :
section size addr
.interp 28 4194928
.note.ABI-tag 32 4194956
.note.gnu.build-id 36 4194988
.gnu.hash 240 4195024
.dynsym 4008 4195264
.dynstr 2093 4199272
.gnu.version 334 4201366
.gnu.version_r 160 4201704
.rela.dyn 720 4201864
.rela.plt 3240 4202584
.init 14 4205824
.plt 2176 4205840
.text 384124 4208016
.fini 9 4592140
.rodata 303556 4592160
.eh_frame_hdr 8540 4895716
.eh_frame 50388 4904256
.gcc_except_table 264 4954644
.tbss 16 7052632
.init_array 16 7052632
.fini_array 8 7052648
.jcr 8 7052656
.data.rel.ro 3992 7052672
.dynamic 480 7056664
.got 216 7057144
.got.plt 1104 7057384
.data 2520 7058496
.bss 80976 7061024
.gnu_debuglink 12 0
Total 849310

ARM bare metal binary linking

I have an ARM board with ROM at 0x80000000 and RAM at 0x20000000. Board starts execution of raw binary code at 0x80000000.
I managed to get a simple ARM assembler program running on it, but I have to use C instead of ASM. I know I will need to use some kind of linker script, and then manually copy .data section to RAM and clear .bss, setup stack etc. but I haven't found a reliable solution how to do this yet, especially the linker script (it's very messy in my opinion).
Also, I can't get the linker to output a raw binary instead of ELF, but it's not a big deal as I can use objcopy later.
Thanks in advance.
This example is for STM32F051 MCU:
Very simple application as "blinky" (without delays):
// define used registers
#define RCC_AHB1 *(volatile unsigned int *)(0x40021014)
#define GPIOC_MODER *(volatile unsigned int *)(0x48000800)
#define GPIOC_BSRR *(volatile unsigned int *)(0x48000818)
// main program
void mainApp() {
RCC_AHB1 = 1 << 19; // enable clock for GPIOC
GPIOC_MODER = 1 << (9 * 2); // set output on GPIOC.P9
while (1) {
GPIOC_BSRR = 1 << 9; // set output on GPIOC.P9
GPIOC_BSRR = 1 << (9 + 16); // clear output on GPIOC.P9
}
}
// variables for testing memory initialisation
int x = 10;
int y = 0;
int z;
Here is also very simple startup file written in C (also will work in C++), which start application mainApp and initialise static variables .data initialised from ROM and .bss only set to zero, there are variables initialised to zero and uninitialised variables.
extern void mainApp();
// external variables defined in linker script
// address in FLASH where are stored initial data for .data section
extern unsigned int _data_load;
// defines start and end of .data section in RAM
extern unsigned int _data_start;
extern unsigned int _data_end;
// defines start and end of .bss section in RAM
extern unsigned int _bss_start;
extern unsigned int _bss_end;
void resetHandler() {
unsigned int *src, *dst;
// copy .data area
src = &_data_load;
dst = &_data_start;
while (dst < &_data_end) {
*dst++ = *src++;
}
// clear .bss area
dst = &_bss_start;
while (dst < &_bss_end) {
*dst++ = 0;
}
mainApp();
while(1);
}
// _stacktop is defined in linker script
extern unsigned int _stacktop;
// vector table, will be placed on begin of FLASH memory, is defined in linker script
// only reset vector defined, need add other used vectors (especially NMI)
__attribute__((section(".vectors"), used)) void *isr_vectors[] = {
&_stacktop, // first vector is not vector but initial stack position
(void *)resetHandler, // vector which is called after MCU start
};
And finaly linker script which define location and sizes of memories, sections for vector, program (text), data (.data and .bss) a stacktop
MEMORY {
FLASH(rx) : ORIGIN = 0x08000000, LENGTH = 64K
SRAM(rwx) : ORIGIN = 0x20000000, LENGTH = 8K
}
SECTIONS {
. = ORIGIN(FLASH);
.text : {
*(.vectors)
*(.text)
} >FLASH
. = ORIGIN(SRAM);
.data ALIGN(4) : {
_data_start = .;
*(.data)
. = ALIGN(4);
_data_end = .;
} >SRAM AT >FLASH
.bss ALIGN(4) (NOLOAD) : {
_bss_start = .;
*(.bss)
. = ALIGN(4);
_bss_end = .;
} >SRAM
_stacktop = ORIGIN(SRAM) + LENGTH(SRAM);
_data_load = LOADADDR(.data);
}
Build this with these command (build and link at once):
$ arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -nostartfiles main.c startup.c -T stm32f051x8.ld -o main.elf
In symbol table is possible to see where are stored data:
$ arm-none-eabi-nm -C -l -n -S main.elf
08000000 00000008 T isr_vectors
08000008 00000034 T mainApp
0800003c 0000005c T resetHandler
08000098 A _data_load
20000000 D _data_start
20000000 00000004 D x
20000004 D _data_end
20000004 B _bss_start
20000004 00000004 B y
20000008 B _bss_end
20000008 00000004 B z
20002000 A _stacktop
Also you can look into listing:
arm-none-eabi-objdump -S main.elf
Raw binary:
arm-none-eabi-objcopy -O binary main.elf main.bin
MEMORY
{
bob : ORIGIN = 0x8000, LENGTH = 0x1000
ted : ORIGIN = 0xA000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > bob
__data_rom_start__ = .;
.data : {
__data_start__ = .;
*(.data*)
} > ted AT > bob
__data_end__ = .;
__data_size__ = __data_end__ - __data_start__;
.bss : {
__bss_start__ = .;
*(.bss*)
} > ted
__bss_end__ = .;
__bss_size__ = __bss_end__ - __bss_start__;
}
of course change the addresses as you see fit. clearly the names of the sections mean nothing, you might try rom and ram if it helps you.
If you were to do something like this
MEMORY
{
rom : ORIGIN = 0x80000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.bss : { *(.bss*) } > ram
.rodata : { *(.rodata*) } > rom
.data : { *(.data*) } > ram
}
and then objcopy it then you are going to end up with a huge file, even if you only have one instruction of .text and one byte of data. because a binary format has to cover everything as in the memory so it will make a file that is 0x80000000+sizeof(text)-0x20000000. If you had one instruction only in ram and one byte of data then the file would be 0x60000004 bytes or 1.6 gig. leave it as an elf and use objdump -D until you have your linker script worked out THEN make a .bin if you really need one. or make an intel hex or s record and again you can examine it to see if it is all in the same address space before trying a binary.
the first key to your problem is the AT
MEMORY
{
bob : ORIGIN = 0x8000, LENGTH = 0x1000
ted : ORIGIN = 0xA000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > bob
.data : { *(.data*) } > ted AT > bob
.bss : { *(.bss*) } > bob
}
it says I want the .data in the address space ted, but place it in the binary in the bob space. it compiles for the ted address space, but the bits are loaded from bob space. exactly what you want. except you dont know how much .data to copy from rom to ram. you have to be super careful where you place the variables in the more complicated one or it wont work right.

Resources