Splitting embedded program in multiple parts in memory - linker

I am working on an embedded system (Stellaris Launchpad) and writing a simple OS (as a hobby project). The used toolchain is gcc-none-eabi.
My next step is to get used to the MPU to allow the kernel to prevent user programs from altering specific data. I have a bunch of C files and I splitted them in two parts: kernel and other.
I have the following linker script to start out with:
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
}
SECTIONS
{
.text :
{
_text = .;
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
_etext = .;
} > FLASH
.data : /*AT(ADDR(.text) + SIZEOF(.text))*/ /*contains initialized data*/
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM AT > FLASH
.bss : AT (ADDR(.data) + SIZEOF(.data)) /*contains unitialized data (should be set to all zero's)*/
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
_start_heap = .;
} > SRAM
_stack_top = ORIGIN(SRAM) + LENGTH(SRAM) - 1; /*The starting point of the stack, at the very bottom of the RAM*/
}
And after reading up on linker scripts I know that I can replace the stars with filenames, and thus start splitting the flash in multiple parts. I would for example create a .kernel.bss section and put all of the kernel object files instead of the stars in that section.
My only problem left is that the kernel is not one file, it is a whole lot of files. And files might be added, removed etc. So how do I do this? How do I change my linker script so that a dynamic first group of files is mapped to the first place and a dynamic second group of files is mapped to a second place?

you know that you can specify what files are used as input for a section?
We use this for separating kernel and application code into fast internal flash, and slower external flash memory, like so:
.kernel_text :
{
build/kernel/*.o (.text*) /*text section from files in build/kernel*/
} > INT_FLASH
.app_text:
{
build/app/*.o(.text*)
} > EXT_FLASH
Section 4.6.4 might be helpful, (describes input sections in more detail)
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/sections.html

I found a solution, allthough it feels a bit hacky. It does work though:
I found out that a linker script is OK with working on .a files if they are statically linked with ar. So lets say you have a buch of .o files that, together form the kernel: a.o, b.o, c.o. Use ar rcs kernel.a a.o, b.o, c.o. kernel.a is now your kernel, which you want to store seperately in memory.
The next thing you need to know is that the * in a linker script is actually a wildcard for everything not used yet. So we can create the following linker script:
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
}
SECTIONS
{
.kernel.text :
{
_kernel_text = .;
KEEP(kernel.a(.isr_vector))
KEEP(kernel.a(_sbrk))
kernel.a(.text*)
kernel.a(.rodata*)
_kernel_etext = .;
_kernel_flash_data = ALIGN(0x4);
} > FLASH
.kernel.data : /*AT(ADDR(.text) + SIZEOF(.text))*/ /*contains initialized data*/
{
_kernel_data = .;
kernel.a(vtable)
kernel.a(.data*)
_kernel_edata = .;
} > SRAM AT > FLASH
.kernel.bss :
{
_kernel_bss = .;
kernel.a(.bss*)
kernel.a(COMMON)
_kernel_ebss = .;
} > SRAM
.text : /*AT (ADDR(.core.text) + SIZEOF(.core.text) + SIZEOF(.core.data))*/
{
_text = .;
*(.text*)
*(.rodata*)
_etext = .;
_flash_data = ALIGN(0x4);
} > FLASH
.data :
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM AT > FLASH
.bss : AT (ADDR(.data) + SIZEOF(.data)) /*contains unitialized data (should be set to all zero's)*/
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
_start_heap = .;
} > SRAM
}
This works but will probably lead to a new problem: the linker treats libraries as.. well, libraries. So if they contain the program start (as in my case) the linker does not actually look for it, the linker only looks trough the library for functions refered to by the actual o files. The solution I found for this is to add the -u <name> flag to the linker invocation. This flag causes a symbol to become undefined, so the linker will look for this symbol plus all symbols that are needed by this synbol.
My invocation, for references sake:
arm-none-eabi-ld -Tlinker_script.ld -nostdlib --entry ResetISR
--gc-sections -u _sbrk -u .isr_vector
-L./lib//hardfp
-L/home/me/gcc-arm-none-eabi/gcc-arm-none-eabi-4_9-2015q1/arm-none-eabi/lib/armv7e-m/fpu
-L/home/me/gcc-arm-none-eabi/gcc-arm-none-eabi-4_9-2015q1/lib/gcc/arm-none-eabi/4.9.3/armv7e-m/fpu
-Lrelease/
-o release/os
./user/obj/release/ledsDance.c.o ./user/obj/release/main.c.o ./validation/obj/release/val_floattest.c.o ./validation/obj/release/val_genTest.c.o ./validation/obj/release/val_gpiotest.c.o ./validation/obj/release/val_iotest.c.o ./validation/obj/release/val_proctest.c.o ./validation/obj/release/val_schedTest.c.o release/kernel.a release/core.a
-ldriver-cm4f
-luartstdio
-lm
-lc
-lgcc

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.

Compile a function to run it in other machine without resolving address dependencies

Im developing a bare metal OS for raspberry pi 1. The main idea of this OS is a simply kernel that will be able to run a function created in other machine and send it to the raspi. The function will use functions that were compilated with the kernel and that reside in memory.
I want to know how can I compile a function that when I will insert the payload in memory in a determinated address it will be able to call system functions and use the data that are defined in the function code.
void function()
{
while (1)
{
uart_puts("Hello\r\n");
}
}
This is my link.ld file and the function will be loaded at __binary_function:
ENTRY(_start)
SECTIONS
{
/* Starts at LOADER_ADDR. */
. = 0x8000;
__start = .;
__text_start = .;
.text :
{
KEEP(*(.text.boot))
*(.text)
}
. = ALIGN(4096); /* align to page size */
__text_end = .;
__rodata_start = .;
.rodata :
{
*(.rodata)
}
. = ALIGN(4096); /* align to page size */
__rodata_end = .;
__data_start = .;
.data :
{
*(.data)
}
. = ALIGN(4096); /* align to page size */
__data_end = .;
__bss_start = .;
.bss :
{
bss = .;
*(.bss)
}
. = ALIGN(4096); /* align to page size */
__bss_end = .;
/*Allocating memory for the heap*/
__heap_start = .;
. = . + 0x1000000; /*4MB Heap section*/
__heap_end = .;
__binary_function = .;
__end = .;
}
My idea is that the kernel will receive the payload via UART and then execute it. The payload must be able to call system functions such us the UART functions and access to the data that is define inside it.
I want to do this automatically with arm-none-eabi-gcc (GCC Toolchain for ARM architecture) that works like GCC and avoiding harcoding the system functions in the payload source.
Thanks!
I solve it using the hardcoding the kernel functions in the payload:
void (* uart_puts)(char *) = (void(*)(char * )) 0x0000000000008248;
I get the 0x0000000000008248 address from the .map file generated in the compilation of the kernel.

Give the priority of the IRAM to a specific source file in C

I'm looking for a way to give the priority of the IRAM to a specific source file and let others source files by default.
From Keil uVision I was able to do it by going in the file options :
I migrated my project to Atollic TrueSTUDIO (generated with CubeMx) and there's no options like these. I found information about how to set where starts the RAM and its size in the linker script STM32F765NG_FLASH.id.
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
}
I imagine that there's maybe a way to modify this file to specify which .c file need the priority on the IRAM, but I don't know where and how to do it.
I also found __ attribute__ that I can use in the variable declaration. When I use it, it compiles, but it breaks some functionalities of the code (it probably override other data).
uint8_t __attribute__((section(".ARM.__at_0x20000000"))) RxSerialDMABuffer[RX_DMA_BUFFER_SIZE] = {0};
uint8_t __attribute__((section(".ARM.__at_0x20001000"))) TxDMABuffer[TX_DMA_BUFFER_SIZE] = {0};
So my question is, how can I set a particular source file to have the priority to use the IRAM before all my others files without the Keil uVision options?
EDIT : This is the complete linker script
/*
*****************************************************************************
**
** File : stm32_flash.ld
**
** Abstract : Linker script for STM32F765NG Device with
** 1024KByte FLASH, 512KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
** Environment : Atollic TrueSTUDIO(R)
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Atollic AB.
** You may use this file as-is or modify it according to the needs of your
** project. This file may only be built (assembled or compiled and linked)
** using the Atollic TrueSTUDIO(R) product. The use of this file together
** with other tools than Atollic TrueSTUDIO(R) is not permitted.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20080000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x00002200; /* required amount of heap */
_Min_Stack_Size = 0x00001200; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
TrueSTUDIO uses the GNU toolchain, so the GNU linker documentation applies. Specifically in the case the part dealing with section placement.
Something like (note the following is a fragment; your real linker script will contain much more or may be organised differently):
MEMORY
{
...
IRAM1 (xrw) : ORIGIN = 0x20020000, LENGTH = 384K
IRAM2 (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
}
SECTIONS
{
DATA_IRAM1 :
{
* (.data)
} > IRAM1 AT > FLASH
BSS_IRAM1 :
{
* (.bss)
} > IRAM1
DATA_IRAM2 :
{
Buffers.o (.data) /* locate Buffers initialised data here */
* (.data)
} > IRAM2 AT > FLASH
BSS_IRAM2 :
{
Buffers.o (.bss) /* locate Buffers zero-int data here */
* (.bss)
} > IRAM2
}
The wild card * (.bss) allows any object module's BSS to be located in the specified section, while Buffers.o (.bss) makes location of Buffers.o BSS explicit. Similarly for .data.
If you took a look at the linker script generated by Keil, you will have seen that it is directly affected by the setting in the GUI dialog and will see similar directives - the ARM linker however uses slightly different syntax than GNU I think, but it may nonetheless help, to see how it organises the memory and location for your specific part - the fragment you have posted seems somewhat generic and does not separate the IRAM for example into its specialist sections such as TCM.
To give the priority of the RAM to my buffers, I loaded them in RAM first.
By going with the file name, the linker was reporting an error for multiple definitions. So I added a section attribute to my buffers like I did in my question, but by giving a section name instead of an address.
uint8_t RxSerialDMABuffer[RX_DMA_BUFFER_SIZE] __attribute__ ((section ("BUFFERS"))) = {0};
uint8_t TxDMABuffer[TX_DMA_BUFFER_SIZE] __attribute__ ((section ("BUFFERS"))) = {0};
After this, I added the new section in RAM before the other uninitialized data.
/* Uninitialized buffers section */
.BUFFERS :
{
* (.BUFFERS)
} >RAM
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
Then I went in the Linker Address Map file and I saw all my buffers with addresses corresponding to my IRAM2 address range, and all the other uninitialized data with the next addresses in IRAM2, then IRAM1.

GDB missing line numbers

I'm debugging an embedded system with the stm32f746vg microcontroller where some speed critical sections of code are loaded in data RAM instead of flash. The rest of the non-critical code is loaded in flash, and the linker puts all of the .text sections in flash by default.
I do this relocation with nasty little function prototypes like this:
int main(void) __attribute__((section(".data")));
This forces main() to be loaded at address 0x2000 0000, which is what I want. Unfortunately, GDB expects main() to be loaded at address 0x0080 0000, where the rest of the program code is. As a result, GDB does not know where the line numbers for main() are. Is there any way to tell GDB "main() is actually at this address" ?
I DO have the newest version of arm-none-eabi-gdb and arm-none-eabi-gcc.
I am running arm-none-eabi-gcc with the -g option.
When I comment out the prototype for main that contains the __attribute__ directive, GDB has no problem finding line numbers.
Below is my linker script:
/* Entry Point */
ENTRY(Reset_Handler)
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
/**
* for the time being, we are going to buffer the image in sram1. sram1 is
* entirely dedicated to buffering images.
* DTCM_RAM will be used for user variables
*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
DTCM_SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
/* RAM1 (xrw) : ORIGIN = 0x20010000, LENGTH = 240K*/
RAM1 (xrw) : ORIGIN = 0x20010000, LENGTH = 245760
RAM2 (xrw) : ORIGIN = 0x2004c000, LENGTH = 16K
ITCM_SRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 16K
}
/* Define output sections */
SECTIONS
{
/* Vectors need to be loaded at the start of flash. */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
/*KEEP (*(.init))*/
/*KEEP (*(.fini))*/
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
_exit = .;
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
/* used by the startup to initialize data */
_sidata = .;
/* Initialized data sections goes into RAM, load LMA copy after code */
.data ORIGIN(DTCM_SRAM) :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} AT > FLASH
__const_data_length__ = SIZEOF(.data);
/* Uninitialized data section */
. = ALIGN(4);
.bss . :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >DTCM_SRAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >DTCM_SRAM
/* ram1 section, vars must be located here explicitly */
/* Example: extern int foo(void) __attribute__ ((section (".ram1"))); */
/* No initialization is offered for this section.*/
.ram1 ORIGIN(RAM1) :
{
*(.ram1)
} >RAM1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
These are my gcc flags
CFLAGS = -gstabs -Wall -std=gnu99 -ffunction-sections -Wno-unused-variable
CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mlong-calls
CFLAGS += -I. -ggdb
CFLAGS += -DHSE_VALUE=$(HSE_VALUE)
CFLAGS += -DUSE_STDPERIPH_DRIVER
You acheive this by placing main() in special code section of your choosing, call it .fast_exec
int main(void) __attribute__((section(".fast_exec")));
Then, in the linker script, place this new section to execute from RAM. It will be copied from FLASH at start-up:
.fast_exec : {
*(.fast_exec)
} > DTCM_SRAM AT> FLASH
You can verify the effect of this, by checking the map file.
Refer to: https://stackoverflow.com/a/15142268/1096140

How to put all static variables coming from a static library in a specific linker script section

I'm working on a stm32 nucleo board. My project is composed of several different libraries.
I would like to put all uninitialized variables coming from static library (mylib.a) in a specific memory section instead of the bss section.
Here is my bss section inside the linker script:
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
I tried adding this section before the bss one:
. = ALIGN(4);
.mybss :
{
/* This is used by the startup in order to initialize the .bss section */
_smybss = .; /* define a global symbol at bss start */
__mybss_start__ = _smybss;
mylib.a:*(.bss)
mylib.a:*(.bss*)
mylib.a:*(COMMON)
. = ALIGN(4);
_emybss = .; /* define a global symbol at bss end */
__mybss_end__ = _emybss;
} >RAM
The compiler does not complain but when I inspect with nm command the generated elf _smybss symbol is at the same address of _emybss symbol. So mybss section is empty.
Do you have any suggestion on how to achive this?
Thanks

Resources