Is there any documentation or an application note on section mapping with the GNUARM-NONE-EABI tool chain?
Is there any documentation or an application note on section mapping with the GNUARM-NONE-EABI tool chain?
Hi,
Due to the nature of the internal RAM of the RZ/A1H I would like to map portions of the code and data into particular pages of internal RAM. Previous Renesas tool chains had #pragma extensions for this purpose application notes on ROM to RAM section mapping were supplied. Does the GNUARM-NONE-EABI tool chain support this? If so is there any documentation or an application note to demonstrate this?
Best regards,
Adam
Hello Adam,
Thank you for replying.
>>The question is how do I tell the linker that the functions in a particular section (which it has assigned an address within the 0x18XX XXXX range) are “mapped” to addresses 0x6XXX XXXX and 0x48XX XXX?
Every loadable or allocatable output section has two addresses:
-VMA (virtual memory address) which is the address the section will have when the code is executed.
-LMA (load memory address), the address at which the section will be loaded.
The documentation for these is in your toolchain installation folder > Documentation > Using ld > 3.1 Basic Linker Script Concepts and the full description of an output section is at 3.6.1 Output Section Description.
E2 studio will create the default linker script (named yourproject_HardwareDebug_auto.gsi) in the HardwareDebug folder after you build the project.
For a new C project, it should look like this:
SECTIONS
{
.fvectors 0x20020000 : AT (0x20020000)
{
KEEP(*(.fvectors))
}
.text 0x20020100 : AT (0x20020100)
{
*(.text)
}
.rvectors :
{
_rvectors_start = .;
KEEP(*(.rvectors))
_rvectors_end = .;
}
.init :
…..
The first address is the VMA and the second is the LMA. You can set your desired address for each one of these.
To apply the changes to the LMA and VMA, simply copy this file in the src folder (where your project .cpp, containing the void main function, file is).
At the Renesas Tool Settings > Linker > Other > Command file override, choose Select External Linker Script(-T), then write the path of your copied default linker script in the field below.
If you modified the VMA with another address, you will see that at the runtime, the code from the specified section will be at the modified address.
If we can be of any more assistance, please let us know.
Best regards,
Darius,
The GNU Tools Support Team
Hello Adam,
Thank you for choosing the GNUARM-NONE-EABI toolchain.
Yes, the GNUARM-NONE-EABI toolchain allows the user to map portions of the code and data into particular pages of internal memory.
The documentation which describe how to write your linker script can be found in the toolchain installation folder > Documentation > GNU Manuals > Using ld > 3. Linker Scripts.
If you don’t like the default implementation, you can write your own linker script as shown in the 3.3 sub-chapter: Simple Linker Script Example.
Another solution for mapping portions of code in particular memory regions is provided by the __attribute__ ((section (“section-name”))) keyword.
You will find the documentation for this attribute in your toolchain installation folder > Documentation > GNU Manuals > Using gcc > 6.30 Declaring Attributes of Functions > section (“section-name”).
By default, all of your written code goes the .text section, but E2studio allows you to create your own sections in the memory regions of your choosing.
You can see the memory sections used by your project by right-clicking it > Renesas Tool Settings -> Linker -> Sections.
There, at the Section tab, you can add more sections by clicking the third button (Add section) below the Section Viewer label.
By clicking it, a new section (named section1) is automatically created and then you can set its details in the right panel: name, starting address, etc.
Then, by using the attribute __attribute__ ((section (“section-name”))) keyword for any declared variable or function, it will map that variable/function in your ‘section1’ defined section.
If you have any more questions, or you require any help with the script, please let us know.
—
Best regards,
Darius,
The GNU Tools Support Team
Hi Darius,
Thanks, I’ll am really struggling with the linker script! The question is about section mapping, I don’t know that the question was particularly clear.
So the linker creates an executable image which is linked to the address 0x1800 0000. Within that image I’d like sections of code and data to be placed at 0x6000 0000 and 0x4800 000.
The code at 0x1800 0000 will initialise the SDRAM, SRAM, L1 Cache, L2 Cache and TLB then copy sections of code and initialised data to the respective destinations.
The question is how do I tell the linker that the functions in a particular section (which it has assigned an address within the 0x18XX XXXX range) are “mapped” to addresses 0x6XXX XXXX and 0x48XX XXX?
Can you make a simple project with a linker script that demonstrates this?
Best regards,
Adam.
Hello Adam,
Please let us know if we have answered your question in full or if you need any further assistance from us.
If we do not receive any feedback within 24 hours, this thread will be closed, but may be re-opened later on if needed.
—
Thank you,
The GNU Tools Support Team
Hi,
Please keep this open as it is still full un-answered & time is required to put a sample project together.
Best regards,
Adam.
Hi Adam,
Just checking in to see if you still need us to keep this open, or if you had submitted the project already in a private support request?
—
Thank you,
The GNU Tools Support Team
Hi,
The project posted was a static library to demonstrate a bug in the compiler. This project does not use the linker & as such would not involve section mapping.
I’ll post another project for demonstration of section mapping.
I’ll also post a separate project to demonstrate all the bugs in the tool integration.
I’m quite busy so please be patient.
Cheers,
Adam.
Hi,
I am still struggling with section mapping in the linker. My linker script looks like this:
/***********************************************************************************
* File: HardwareDebug.ld
* Author: Adam Fullerton
* Date: 19/04/2016
*
* $Workfile: $
* $Revision: $
* $Project: $ Swarm Systems Hawk
* $Compiler: $ GNUARM-NONEV16.01-EABI
* $Target: $ RZ/A1H
* $State: $ Stab
* (‘Exp’erimental/’Stab’le/’Rel’eased)
* $Date $
*
* Description : Linker script file for RZA1/H RSK HardwareDebug build
*
* (C) Swarm Systems Ltd. 2016 All rights reserved.
*
* A: 1 The Mount, Old Blandford Road, Salisbury, Wiltshire. SP2 8BZ
* T: 01722 341 027
* E: adam@ardware.co.uk
* W: http://www.ardware.co.uk
*
**********************************************************************************/
/**********************************************************************************
Set the output format
***********************************************************************************/
OUTPUT_FORMAT(“elf32-littlearm”, “elf32-bigarm”, “elf32-littlearm”)
OUTPUT_ARCH(arm)
ENTRY(start)
/**********************************************************************************
Define the memory available on the RSK
***********************************************************************************/
MEMORY
{
/* On-Chip Data retention RAM >>> DISABLED AT RESET <<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ROM IMAGE <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SRAM
/******************************************************************************
System initialisation
******************************************************************************/
.system_init :
{
/* We need the code that initialises the system up until
the point that the section initialisation has taken place
to reside in one section which is not mapped to another
place. This section has all the code & data to do this */
*reset_handler.o (.text) . = ALIGN(0x04);
*peripheral_init_basic.o (.text) . = ALIGN(0x04);
*rza_io_regrw.o (.text) . = ALIGN(0x04);
/* Put the code from the initsect function here */
*initsect.o (.text) . = ALIGN(0x04);
/* Also put the initialised data section here */
*initsect.o (.init_data) . = ALIGN(0x04);
} > SRAM
/******************************************************************************
Executable code & read only data
******************************************************************************/
.code :
{
gExecutableCodeRomStart = .;
gExecutableCodeRamStart = .;
PROVIDE_HIDDEN (__exidx_start = .);
*(.init)
PROVIDE_HIDDEN (__exidx_end = .);
*(.text)
*(.fini)
*(.jcr)
__CTOR_LIST__ = .;
. = ALIGN(2);
__ctors = .;
*(.ctors)
__ctors_end = .;
__CTOR_END__ = .;
__DTOR_LIST__ = .;
___dtors = .;
*(.dtors)
___dtors_end = .;
__DTOR_END__ = .;
. = ALIGN(2);
_mdata = .;
_srodata = .;
*(.rodata)*(.rodata.*) . = ALIGN(0x04);
_erodata = .;
gExecutableCodeRomEnd = .;
} > SRAM
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> RAM IMAGE <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<SRAM
/* TODO: Move */
.bss :
{
gUnintialisedDataRamStart = .;
*(.bss)
*(.bss.**)
*(COMMON)
gUnintialisedDataRamEnd = .;
} > SRAM
/******************************************************************************
Heaps
******************************************************************************/
.sram_heap_start (NOLOAD) :
{
/* The L1 cache line size is 32 bytes. To avoid cache synchronisation
problems the malloc functions will align allocations to 32 byte boundaries.
However in order for the scheme to work the area assigned to the heap
must be aligned to a 32byte boundary as well */
gSRamHeapStart = ALIGN(0x20);
} > SRAM
.sram_heap_end (NOLOAD) :
{
gSRamHeapEnd = .;
} > SRAM_END
.sdram_heap_start (NOLOAD) :
{
/* The L2 cache line size is 32 bytes. To avoid cache synchronisation
problems the malloc functions will align allocations to 32 byte boundaries.
However in order for the scheme to work the area assigned to the heap
must be aligned to a 32byte boundary as well */
gSDRamHeapStart = .;
} > SDRAM
.sdram_heap_end (NOLOAD) :
{
gSDRamHeapEnd = ALIGN(0x20);
} > SDRAM_END
/******************************************************************************
Stacks & TLB
******************************************************************************/
/* The application does not require the data retention function.
The area is not usable until the processor is running the application
code as it is disabled on reset. Assign the stacks & TLB to this memory
which would otherwise be unused. Ensure System control register 3 SYSCR3
is initialised before stack pointers are loaded */
.irq_stack (NOLOAD):
{
irq_stack_start = .;
. += 8k;
. = ALIGN(0x08);
irq_stack_end = .;
} >RRAM
.fiq_stack (NOLOAD):
{
fiq_stack_start = .;
. += 4k;
. = ALIGN(0x08);
fiq_stack_end = .;
} >RRAM
.svc_stack (NOLOAD):
{
PROVIDE(svc_stack_start = .);
. += 8k;
. = ALIGN(0x08);
svc_stack_end = .;
} >RRAM
.abt_stack (NOLOAD):
{
abt_stack_start = .;
. += 4k;
. = ALIGN(0x08);
abt_stack_end = .;
} >RRAM
.program_stack (NOLOAD):
{
program_stack_start = .;
. += 8k;
. = ALIGN(0x08);
program_stack_end = .;
} >RRAM
.ttb_mmu1 :
{
ttb_mmu1_base = .;
. += 32k;
. = ALIGN(0x04);
ttb_mmu1_end = .;
} >RRAM
}
/**********************************************************************************
EOF
***********************************************************************************/
The section initialisation code looks like this:
/***********************************************************************************
* File: initsect.c
* Author: Adam Fullerton
* Date: 20/07/2016
*
* $Workfile: $
* $Revision: $
* $Project: $ Swarm Systems Hawk
* $Compiler: $ GNUARM-NONEV16.01-EABI
* $Target: $ RZ/A1H
* $State: $ Stab
* (‘Exp’erimental/’Stab’le/’Rel’eased)
* $Date $
*
* Description : Section initialisation function
*
* (C) Swarm Systems Ltd. 2016 All rights reserved.
*
* A: 1 The Mount, Old Blandford Road, Salisbury, Wiltshire. SP2 8BZ
* T: 01722 341 027
* E: adam@ardware.co.uk
* W: http://www.ardware.co.uk
*
**********************************************************************************/
/***********************************************************************************
External symbols defined in the linker script
***********************************************************************************/
extern char gInitialisedDataRomStart;
extern char gInitialisedDataRomEnd;
extern char gInitialisedDataRamStart;
extern char gExecutableCodeRomStart;
extern char gExecutableCodeRomEnd;
extern char gExecutableCodeRamStart;
extern char gUnintialisedDataRamStart;
extern char gUnintialisedDataRamEnd;
/***********************************************************************************
Constant data
***********************************************************************************/
/* ROM to RAM mapped section table for C/C++ run time library initialisation */
static const struct _DSEC
{
/* Start address of the initialised data section in ROM */
void *pvRomStart;
/* End address of the initialised data section in ROM */
void *pvRomEnd;
/* Start address of the initialised data section in RAM */
void *pvRamStart;
} gpCopyTable[] __attribute__((section(“.init_data”))) =
{
/* The initialised data section copied to RAM */
{
&gInitialisedDataRomStart,
&gInitialisedDataRomEnd,
&gInitialisedDataRamStart
},
/* The code section copied to RAM */
{
&gExecutableCodeRomStart,
&gExecutableCodeRomEnd,
&gExecutableCodeRamStart
},
/* TODO: Add all initialised sections here */
};
/* The non-initialised data section table for C run time library
initialisation */
static const struct _BSEC
{
/* Start address of non-initialised data section */
void *pvRamStart;
/* End address of non-initialised data section */
void *pvRamEnd;
} gpZeroTable[] __attribute__((section(“.init_data”))) =
{
{
&gUnintialisedDataRamStart,
&gUnintialisedDataRamEnd
},
/* TODO: Add all other sections here */
};
/***********************************************************************************
Public Functions
***********************************************************************************/
/***********************************************************************************
* Function Name: initsect
* Description : Function to perform section initialisation
* Arguments : none
* Return Value : none
***********************************************************************************/
void initsect(void)
{
register unsigned int uiCount;
{
register struct _DSEC *pCopyTable = (struct _DSEC*)gpCopyTable;
/* Calculate the number of entries in the mapped Data Table */
uiCount = sizeof(gpCopyTable) / sizeof(struct _DSEC);
while (uiCount–)
{
/* Allow a RAM based build (HardwareDebug) to link the initialised
data so that no copying is required – with the caveat that the
code will only be run once before being down loaded to RAM again.
Therefore check that the ROM and RAM are not the same before
performing the copy */
if (pCopyTable->pvRomStart != pCopyTable->pvRamStart)
{
register char *pbyDestination = (char*)pCopyTable->pvRamStart;
register char *pbySource = (char*)pCopyTable->pvRomStart;
register unsigned int uiLength
= (unsigned int)(pCopyTable->pvRomEnd – pCopyTable->pvRomStart);
/* Copy the section */
while (uiLength–)
{
*pbyDestination++ = *pbySource++;
}
}
pCopyTable++;
}
}
{
register struct _BSEC *pZeroTable = (struct _BSEC*)gpZeroTable;
/* Calculate the number of entries in the Non-initialised Data Table */
uiCount = sizeof(gpZeroTable) / sizeof(struct _BSEC);
while (uiCount–)
{
register char *pbyDestination = pZeroTable->pvRamStart;
register unsigned int uiLength
= (unsigned int)(pZeroTable->pvRamEnd – pZeroTable->pvRamStart);
/* Initialise the section to 0 */
while (uiLength–)
{
*pbyDestination++ = (char)0;
}
pZeroTable++;
}
}
}
/***********************************************************************************
End of function initsect
***********************************************************************************/
/***********************************************************************************
End Of File
***********************************************************************************/
However I cannot figure out the syntax to map the sections .code and .data into the memory area SDRAM.
I have tried things like:
.code : AT(ADDR(.mapped_code))
{
gExecutableCodeRomStart = .;
gExecutableCodeRamStart = .;
PROVIDE_HIDDEN (__exidx_start = .);
*(.init)
PROVIDE_HIDDEN (__exidx_end = .);
*(.text)
*(.fini)
*(.jcr)
__CTOR_LIST__ = .;
. = ALIGN(2);
__ctors = .;
*(.ctors)
__ctors_end = .;
__CTOR_END__ = .;
__DTOR_LIST__ = .;
___dtors = .;
*(.dtors)
___dtors_end = .;
__DTOR_END__ = .;
. = ALIGN(2);
_mdata = .;
_srodata = .;
*(.rodata)*(.rodata.*) . = ALIGN(0x04);
_erodata = .;
gExecutableCodeRomEnd = .;
} > SRAM
.mapped_code (NOLOAD) :
{
gExecutableCodeRamStart .= ALIGN(0x04);
SIZEOF(.code)
} > SDRAM
but ld just barfs on the syntax.
Can you show me how to modify the script to achieve this?
Cheers,
Adam.
Hi,
It appears that the symbols in the linker script are interpreted as formatting commands in this box. The question above, in plain text, can be found here:
http://www.ardware.co.uk/linker_question.txt
Cheers,
Adam.
Hello Adam,
Thank you for providing this information.
If you want your .code and .data section to be loaded from SDRAM, simply add AT > SDRAM after the > SRAM instruction from the section’s end.
e.g:
code :
{
…
} > SRAM AT > SDRAM
That will ensure that the section will be loaded at start of the SDRAM memory even though its relocation address is SRAM.
A more detailed description of a linker script section can be found at: https://sourceware.org/binutils/docs/ld/Output-Section-Description.html#Output-Section-Description
If you believe we can be of any further assistance, please feel free to contact us.
—
Kind regards,
Darius,
The GNU Tools Support Team
Hi,
Thank you for your continued support. In this case I am trying to map .code which is loaded into SRAM to SDRAM. So I need the following addresses from the linker:
gExecutableCodeRomStart = The start address the linker has loaded the code into SRAM
gExecutableCodeRomEnd = The end address the linker had loaded the code into SRAM
gExecutableCodeRamStart = The start address the linker has located the code to run at in SDRAM
So how do I get these addresses from the linker?
Best regards,
Adam.
Hello Adam,
Thank you for your reply.
If you want to load the .code section into SRAM, then copy it to SDRAM, and you will have access to the begin\end addresses of this region. I suggest to modify your .code section from your linker script as follows:
.code :
{
gExecutableCodeRamStart = .;
gExecutableCodeRomStart = LOADADDR (.code);
PROVIDE_HIDDEN (__exidx_start = .);
*(.init)
PROVIDE_HIDDEN (__exidx_end = .);
*(.text)
*(.fini)
*(.jcr)
__CTOR_LIST__ = .;
. = ALIGN(2);
__ctors = .;
*(.ctors)
__ctors_end = .;
__CTOR_END__ = .;
__DTOR_LIST__ = .;
___dtors = .;
*(.dtors)
___dtors_end = .;
__DTOR_END__ = .;
. = ALIGN(2);
_mdata = .;
_srodata = .;
*(.rodata)*(.rodata.*) . = ALIGN(0x04);
_erodata = .;
gExecutableCodeRamEnd = .;
gExecutableCodeRomEnd = LOADADDR (.code) + SIZEOF(.code);
} > SDRAM AT > SRAM
The assignments:
gExecutableCodeRamStart = .;
gExecutableCodeRamEnd = .;
gExecutableCodeRomStart = LOADADDR (.code);
gExecutableCodeRomEnd = LOADADDR (.code) + SIZEOF(.code);
mean the following:
* gExecutableCodeRamStart will have, when the program is running, the start address value of the .code section
* gExecutableCodeRamEnd will have,when the program is running. the end value of the.code section
* gExecutableCodeRomStart will have the address from where the .code is copied in the SDRAM.
* gExecutableCodeRomEnd will have the address from where the .code + sizeof(.code) is copied in the SDRAM.
>>So how do I get these addresses from the linker?
If you want to use them in a .c file, simply declare them as follows:
extern char *gExecutableCodeRomStart;
If you believe we can be of any further assistance, please feel free to contact us.
—
Kind regards,
Darius,
The GNU Tools Support Team