linker script, what do region attributes do exactly? - linker-scripts

In linker scripts I typically see that flash is marked with rx
MEMORY
{
/* Define each memory region */
PROGRAM_FLASH (rx) : ORIGIN = 0x60000000, LENGTH = 0x400000 /* 4M bytes (alias Flash) */
SRAM_DTC (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000 /* 64K bytes (alias RAM) */
SRAM_ITC (rwx) : ORIGIN = 0x0, LENGTH = 0x10000 /* 64K bytes (alias RAM2) */
SRAM_OC (rwx) : ORIGIN = 0x20200000, LENGTH = 0x20000 /* 128K bytes (alias RAM3) */
BOARD_SDRAM (rwx) : ORIGIN = 0x80000000, LENGTH = 0x1e00000 /* 30M bytes (alias RAM4) */
NCACHE_REGION (rwx) : ORIGIN = 0x81e00000, LENGTH = 0x200000 /* 2M bytes (alias RAM5) */
}
But I can still erase and write sections in flash when my app is running. What does this r attribute imply/limit/mean then?

Related

How to force my section in the very end of flash?

I have my linker script with such memory layout
MEMORY{
ram : ORIGIN = 0x0, LENGTH = 0x1000 /* 4KB of RAM starting at address 0x0 */
flash : ORIGIN = 0x20000000, LENGTH = 0xC000 /* 48KB of flash starting at address 0x20000000 */
}
and I want to add two section in the very end of my flash(let's say .section1 and .section2)
but I don't know the length of my section unless I compile it
In my expectation, my flash layout will look like this:
start address
section
0x20000000
.text
0x20000000+.text size
.data
0x20000000+.text size + .data size
.mdata
0x20000000+.text size + .data size + .mdata
(empty flash)
0x2000C000-.section2 size - section1 size
.section1
0x2000C000-.section2 size
.section2
How should I do in my linker script?
I don't know how to wrote it for now I just force my address like this. but its not what I want.
.section1 :{
*(.section1)
} >flash :AT (0x2000A000)
.section2 :{
*(.section2)
} >flash :AT (0x2000B000)

STM32F407ze throws hard fault on executing code from RAM

I am trying to execute a simple code from RAM, but for some reason the program halts/throws hard fault. I am using CCMRAM for my data, heap and stack while SRAM1 for executing code. Here is my linker script and startup file.
LinkerScript.ld
/*
******************************************************************************
**
** File : LinkerScript.ld
**
** Author : Auto-generated by Ac6 System Workbench
**
** Abstract : Linker script for STM32F407ZETx Device from STM32F4 series
** 112Kbytes SRAM1
** 16Kbytes SRAM2
** 64Kbytes CCMRAM
** 512Kbytes ROM
**
** 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
**
** Distribution: The file is distributed �as is,� without any warranty
** of any kind.
**
*****************************************************************************
** #attention
**
** <h2><center>© COPYRIGHT(c) 2019 Ac6</center></h2>
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
** 1. Redistributions of source code must retain the above copyright notice,
** this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright notice,
** this list of conditions and the following disclaimer in the documentation
** and/or other materials provided with the distribution.
** 3. Neither the name of Ac6 nor the names of its contributors
** may be used to endorse or promote products derived from this software
** without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
/*_estack = 0x2001C000; /* start of SRAM2 */
_estack = 0x10010000; /* end of CCMRAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Memories definition */
MEMORY
{
SRAM1 (xrw) : ORIGIN = 0x20000000, LENGTH = 112K
SRAM2 (xrw) : ORIGIN = 0x2001C000, LENGTH = 16K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
/* Sections */
SECTIONS
{
/* The startup code into ROM memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/*sram1 section for code and data*/
_sisram1 = LOADADDR(.sram1);
.sram1 :
{
. = ALIGN(4);
_s_sram1 = .;
*(.sram1);
*(.sram1*);
. = ALIGN(4);
_e_sram1 = .;
} > SRAM1 AT >FLASH
/*sram2 section for code and data*/
_sisram2 = LOADADDR(.sram2);
.sram2 :
{
. = ALIGN(4);
_s_sram2 = .;
*(.sram2);
*(.sram2*);
. = ALIGN(4);
_e_sram2 = .;
} > SRAM2 AT >FLASH
/* The program code and other data into FLASH memory */
.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 into FLASH memory*/
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : {
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} > FLASH
.ARM : {
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >FLASH
.preinit_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >FLASH
.init_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FLASH
.fini_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >FLASH
/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections into RAM memory */
.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 */
} >CCMRAM AT> FLASH
/* Uninitialized data section into RAM memory */
. = 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;
} >CCMRAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >CCMRAM
/* Remove information from the compiler libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
And here is part of my startup file
/**
******************************************************************************
* #file startup_stm32.s dedicated to STM32F407ZETx device
* #author Ac6
* #version V1.0.0
* #date 2019-03-30
******************************************************************************
*/
.syntax unified
.cpu cortex-m4
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
/**
* #brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* #param None
* #retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr r0, =_estack
mov sp, r0 /* set stack pointer */
/* Copy the data segment initializers from flash to SRAM */
ldr r0, =_sdata
ldr r1, =_edata
ldr r2, =_sidata
movs r3, #0
b LoopCopyDataInit
CopyDataInit:
ldr r4, [r2, r3]
str r4, [r0, r3]
adds r3, r3, #4
LoopCopyDataInit:
adds r4, r0, r3
cmp r4, r1
bcc CopyDataInit
/* Zero fill the bss segment. */
ldr r2, =_sbss
ldr r4, =_ebss
movs r3, #0
b LoopFillZerobss
FillZerobss:
str r3, [r2]
adds r2, r2, #4
LoopFillZerobss:
cmp r2, r4
bcc FillZerobss
///////////// Following blocks are for SRAM1 /////////////////////
// Copy from flash to SRAM1
ldr r0, =_s_sram1
ldr r1, =_e_sram1
ldr r2, =_sisram1
movs r3, #0
b LoopCopySRAM1Init
CopySRAM1Init:
ldr r4, [r2, r3]
str r4, [r0, r3]
adds r3, r3, #4
LoopCopySRAM1Init:
adds r4, r0, r3
cmp r4, r1
bcc CopySRAM1Init
// End of data copy from Flash to SRAM1
// Zero fill the SRAM1 segment.
ldr r2, =_s_sram1
b LoopFillZeroSRAM1
FillZeroSRAM1:
movs r3, #0
str r3, [r2]
adds r2, r2, #4
LoopFillZeroSRAM1:
ldr r3, = _e_sram1
cmp r2, r3
bcc FillZeroSRAM1
//////////////// End of SRAM1 Blocks /////////////////
///////////// Following blocks are for SRAM2 /////////////////////
// Copy from flash to SRAM2
ldr r0, =_s_sram2
ldr r1, =_e_sram2
ldr r2, =_sisram2
movs r3, #0
b LoopCopySRAM2Init
CopySRAM2Init:
ldr r4, [r2, r3]
str r4, [r0, r3]
adds r3, r3, #4
LoopCopySRAM2Init:
adds r4, r0, r3
cmp r4, r1
bcc CopySRAM2Init
// End of data copy from Flash to SRAM2
// Zero fill the SRAM2 segment.
ldr r2, =_s_sram2
b LoopFillZeroSRAM2
FillZeroSRAM2:
movs r3, #0
str r3, [r2]
adds r2, r2, #4
LoopFillZeroSRAM2:
ldr r3, = _e_sram2
cmp r2, r3
bcc FillZeroSRAM2
//////////////// End of SRAM2 Blocks /////////////////
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
LoopForever:
b LoopForever
Can anybody please help me if there is any bug here. Lets say, for now we are only trying to run code from SRAM1 since that is the one which is connected to I-bus and D-bus ports of the Cortex M4 on this MCU. With respect to the picture below, I would expect bl to be jumping to beginning of SRAM1.. Can you please shed some light on it:
According to the screen captures, your code is jumping to SRAM (as expected) but there is no code in SRAM (MOV R0 R0 indicates the memory is filled with 0s) hence the hardFault.
You have to copy from Flash to RAM the code that you want to execute in RAM.

Is there a limit above max_dgram_qlen and wmem_{max,default}?

I am trying to determinate the different limits of the unix datagram sockets, as I am using it as IPC for my project.
The obscure thing I want to control is the size of my socket's internal buffer :
I want to know how many datagrams I can send before my socket would block.
I've understood that 2 differents limits affect the size of the socket's buffer :
/proc/sys/net/core/wmem_{max, default} sets the max (-default) size of a socket's writing buffer
/proc/sys/net/unix/max_dgram_qlen sets the maximum number of datagram the buffer can hold
I know that /proc/sys/net/core/rmem_{max, default} sets the max (-default) size of a socket's reading buffer but as I am working on local unix socket it doesn't seem to have a impact.
I have set wmem_{max, default} to 136314880 (130 MB) and max_dgram_qlen to 500000.
And wrote a small program where the sender socket only sends fixed size datagram to the receiver socket until is would block, I then print the size and number of datagram I was able to send.
Here is the code I used :
#include <err.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
/* Payload size in bytes. */
#define PAYLOAD_SIZE 100
#define CALL_AND_CHECK(syscall) \
if (syscall < 0) { err(1, NULL); }
int main(void)
{
int receiver_socket_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
if (receiver_socket_fd < 0)
err(1, NULL);
char* binding_path = "test_socket";
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, binding_path, sizeof(addr.sun_path));
/* Check if the file exists, if yes delete it ! */
if (access(binding_path, F_OK) != -1) {
CALL_AND_CHECK(unlink(binding_path));
}
CALL_AND_CHECK(bind(receiver_socket_fd, (struct sockaddr const*) &addr, sizeof(addr)));
int sender_socket_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
if (sender_socket_fd < 0)
err(1, NULL);
CALL_AND_CHECK(connect(sender_socket_fd, (struct sockaddr const*) &addr, sizeof(addr)));
struct payload { char data[PAYLOAD_SIZE]; };
/* Create test payload with null bytes. */
struct payload test_payload;
memset(&test_payload.data, 0, PAYLOAD_SIZE);
ssize_t total_size_written = 0;
ssize_t size_written = 0;
do {
size_written = write(sender_socket_fd, (const void *) &test_payload, PAYLOAD_SIZE);
if (size_written > 0)
total_size_written += size_written;
} while (size_written > 0);
printf("socket_test: %zu bytes (%ld datagrams) were written before blocking, last error was :\n", total_size_written, total_size_written / PAYLOAD_SIZE);
perror(NULL);
CALL_AND_CHECK(unlink(binding_path));
CALL_AND_CHECK(close(sender_socket_fd));
CALL_AND_CHECK(close(receiver_socket_fd));
return 0;
}
I was expecting to reach either the max size in bytes of the socket (here 130MB) or the max number of datagram I set (500 000).
But the actual result is that I am only able to write 177494 datagrams before being blocked.
I can change the size of my payload it's always the same result (as long as I don't reach the maximum size in bytes first). So it seems that I am hitting a limit above max_dgram_qlen and wmem_{max, default} that I can't found.
I have of course tried to investigate ulimit or limits.conf without success. ulimit -b doesn't even work on my machine (says "options not found" and returns).
I am working on Debian 10 (buster) but have launched my test program on different OS with the same result : I hit a limit of datagram that I don't know about.
Do you have any idea of which limit I didn't see and I am reaching ? And if I can read or modify this limit ?

cJSON can`t parse more than 4 elements

Trying to use cJSON parser with STM32F103C8T6 and KEIL IDE
The problem is that the parser works pretty well with up to 4 elements of the JSON string, when trying to add the fifth element it gives up.
This code seems to be OK:
#include "cJSON.h"
const char * my_json_string =
"{\"device\":\"16\",\"class\":\"master\",\"call\":\"start\",\"ar1\":\"10\"}";
int main (void){
char * device;
char * cls;
char * call;
char * arg1;
cJSON * root = cJSON_Parse(my_json_string);
if (root == NULL){
printf(cJSON_GetErrorPtr());
return 0;
}
cJSON * dev = cJSON_GetObjectItem(root, "device");
cJSON * cla = cJSON_GetObjectItem(root, "class");
cJSON * cl = cJSON_GetObjectItem(root, "call");
cJSON * ar1 = cJSON_GetObjectItem(root, "ar1");
device = dev->valuestring;
cls = cla->valuestring;
call = cl->valuestring;
arg1 = ar1->valuestring;
printf (device);
printf (cls);
printf (call);
printf (arg1);
}
When I add the fifth pair of key-value to the string
const char * my_json_string =
"{\"device\":\"16\",\"class\":\"master\",\"call\":\"start\",\"ar1\":\"10\",\"ar2\":\"20\"}";
it throws an error pointer
,"ar2":"20"}
The same code, compiled with NetBeans IDE for the desktop works fine.
Here is the RAM map of the STM32, I see no problems here:
Execution Region RW_IRAM1 (Base: 0x20000000, Size: 0x00000ea0, Max: 0x00005000, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x20000000 0x00000014 Data RW 5 .data system_stm32f10x.o
0x20000014 0x00000014 Data RW 18 .data main.o
0x20000028 0x00000008 Data RW 35 .data usart_f10x.o
0x20000030 0x0000000b Data RW 56 .data led_matrix_64x32.o
0x2000003b 0x00000001 PAD
0x2000003c 0x00000004 Data RW 63 .data time_f10x.o
0x20000040 0x00000014 Data RW 155 .data cjson.o
0x20000054 0x00000004 Data RW 357 .data mc_w.l(mvars.o)
0x20000058 0x00000004 Data RW 358 .data mc_w.l(mvars.o)
0x2000005c 0x00000041 Zero RW 34 .bss usart_f10x.o
0x2000009d 0x00000003 PAD
0x200000a0 0x00000800 Zero RW 54 .bss led_matrix_64x32.o
0x200008a0 0x00000200 Zero RW 7 HEAP startup_stm32f10x_md.o
0x20000aa0 0x00000400 Zero RW 6 STACK startup_stm32f10x_md.o
The problem is that 512 kB for the HEAP size was too low.

conditional statements for linker command language LD

Are there conditional statements for the GNU LD linker command language?
Context: I am developing firmware for an arm cortex m0+, which consists of a bootloader and an application. Both are compiled and flashed to target in separate projects, but I use a framework with symbolic links to the drivers, makefile and loader scripts so that I can reuse those for every app I make without copying these files for each app.
Currently I have two loader files, for bootloader and application (makefile automatically specifies the appropriate one), with memory assigment as follows:
bootloader
MEMORY {
flash (rx) : ORIGIN = 0x00000000, LENGTH = 16K
ram (rwx) : ORIGIN = 0x1FFFF000, LENGTH = 16K
}
app
MEMORY {
flash (rx) : ORIGIN = 0x00004000, LENGTH = 112K
ram (rwx) : ORIGIN = 0x1FFFF000, LENGTH = 16K
}
Like the makefile, I want to merge these to something like this (using C expressions to clarify)
MEMORY {
#ifdef(bootloaderSymbol)
flash (rx) : ORIGIN = 0x00000000, LENGTH = 16K
#else
flash (rx) : ORIGIN = 0x00004000, LENGTH = 112K
#endif
ram (rwx) : ORIGIN = 0x1FFFF000, LENGTH = 16K
}
Although its not its primary purpose, you can always run the C preprocessor
(cpp) on your linker scripts:
#if defined(MACHINE1)
# define TARGET_ADDRESS 0x80000000
# define SDRAM_START xxx
# define SDRAM_SIZE yyy
# define ROMFLAGS rx
#elif defined(MACHINE2)
# define TARGET_ADDRESS 0x40000000
# define SDRAM_START zzz
# define SDRAM_SIZE aaa
# define ROMFLAGS rwx
#else
# error unknown machine
#endif
MEMORY
{
rom (ROMFLAGS) : ORIGIN = TARGET_ADDRESS, LENGTH = 0x00100000
ram (WX) : ORIGIN = SDRAM_START + SDRAM_SIZE - 0x00200000, LENGTH = 0x00100000
driver_ram (WX) : ORIGIN = SDRAM_START + SDRAM_SIZE - 0x00100000, LENGTH = 0x00100000
}
...
You just need to make sure your macros don't collide with linker script syntax. Then save your linker script as xxx.lk.in (instead of xxx.lk) and add a recipe to your Makefile:
xxx.lk: xxx.lk.in
$(CPP) -P $(INCLUDE) -D$(MACHINE) $< $#
All that's left to do is to add xxx.lk as dependency to your final executables build recipe. I'm using similar processes on many of my projects successfully.
I think you can try "DEFINED(symbol)" according to https://sourceware.org/binutils/docs/ld/Builtin-Functions.html
Also, please don't forget to pass "--defsym=bootloaderSymbol=1" to ld.
MEMORY {
flash (rx) : ORIGIN = DEFINED(bootloaderSymbol) ? 0x00000000 : 0x00004000, LENGTH = DEFINED(bootloaderSymbol) ? 112K : 16K
ram (rwx) : ORIGIN = 0x1FFFF000, LENGTH = 16K
}
I've gone down this same path before, and later found out there's an ld command line argument to specify segment origin, which alleviates the need to figure it out in the linker script. From man page:
-Tbss=org
-Tdata=org
-Ttext=org
Same as --section-start, with ".bss", ".data" or ".text" as the section name.
So in your case, you would have -Ttext=0 (bootloader) or -Ttext=0x00004000 (app)