STM32 ExtRAM GCC-MAP file - gcc

I use STM32F417 with external 512*16 RAM under FreeRTOS. When I see a MAP file the address of used memory are still in the internal RAM.
RTOS Heap def:
> static unsigned char ucHeap[ 60*1024 ]__attribute__ > ((section(".ExRam")));
arm-gcc-link.ld file:
> rom (rx) : ORIGIN = 0x08000000, LENGTH = 0x00100000
> ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
>ram2 (rwx) : ORIGIN = 0x60000000, LENGTH = 0x00100000
>...
>ExRam (NOLOAD): { *(.ExRam.) } > ram2
>...
MAP File:
> .ExRam 0x60000000 0xf000
>*(.ExRam.)
>.ExRam 0x60000000 0xf000 ..\obj\heap_4.o
>
> .ARM.extab *(.ARM.extab * .gnu.linkonce.armextab.*)
> 0x6000f000 __exidx_start = .
Variable , Why not in 0x6000000 area?:
>.bss 0x200053ac 0x2c ..\obj\tcp_in.o
>.bss 0x200053d8 0x4 ..\obj\raw.o
>.bss 0x200053dc 0x10 ..\obj\ip_addr.o
>.bss 0x200053ec 0x100 ..\obj\ssl_ciphersuites.o
>.bss 0x200054ec 0x678 ..\obj\dns.o
>.bss 0x20005b64 0x8 ..\obj\lwip_timers.o

The heap is used by malloc to allocate memory dynamically, at run time. The linker creates the map file at build time, before your code is running. The linker knows only about variables that are defined at compile time. The linker has no knowledge of how the heap will be used at run-time. Therefore the map file cannot possibly itemize the variables that may be created in the heap.
The variables that are listed in the map file in the .bss and .data sections are defined at compile time and statically allocated. They don't appear in the heap because that is not what the heap is for.

OK,
I found that in the MAP file are not listed variables located in the extRAM heap. It means that object listed in RAM are lower size if there are variables located in the heap in extRAM but are not listed under heap address (0x6000000) same way like variables/object located in the internal RAM.

Related

Is there a way to force a variable to be placed at top of .bss section?

I am using GCC on a Cortex M0 from NXP.
I have a non-initialized buffer which needs to be placed at 512 byte boundary due to DMA access restrictions:
DMA_CH_DESCRIPTOR_T __attribute__ ((aligned (512))) Chip_DMA_Table[MAX_DMA_CHANNEL];
This will end up in .bss section, but of course, due to alignment, there will be some lost space before. I know that .bss starts (in my MCU) at 0x10000000 which is already 512 aligned.
So the big question is how can I force my buffer to be the first symbol in .bss ?
I already tried like this but it doesn't work
.bss : ALIGN(4)
{
_bss = .;
PROVIDE(__start_bss_RAM = .) ;
PROVIDE(__start_bss_SRAM = .) ;
drv_dma.o (.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4) ;
_ebss = .;
PROVIDE(__end_bss_RAM = .) ;
PROVIDE(__end_bss_SRAM = .) ;
PROVIDE(end = .);
} > SRAM AT> SRAM
Note: I can see several potential resolves:
defining my own .bss_top for example, and modify my startup script to consider it as a separate .bss and initialize it.
defining a separate section BEFORE actual .bss and initialize my buffer from code somewhere
memset(...)
But I said it's worth to ask, maybe there is a simple linker catch on this one.
Thank you,

How to specify linker option to not use a particular address space while generating the vmlinux kernel Image?

I have an address space in RAM that is used for something else -
0x00100000 to - 4096 bytes. I want to specify a linker option in Yocto , linux kernel to not use that address space starting from 0x00100000 to - 4096 bytes.
I am unsure about the syntax here like -
ROM 0 (NOLOAD)
SECTIONS
{
ROM 0 (NOLOAD) : { 0x00100000 - 4096 }
. = KERNELBASE;
_text = .;
_stext = .;
/*

ARM bare-metal program compilation -control flash writes

I'm trying to compile some C code to run on an ARMv6 simulator, with FLASH memory starting # 0x0 and RAM starting at 0x800000. Right now, I can pass binary files off the the simulator just fine...
However, I want the instructions generated to not include any writes to flash memory, and only operate within RAM memory (after copying RAM). Is this possible?
I am using the GNU toolchain to compile.
This is my current linker script:
MEMORY
{
rom(rx) : ORIGIN = 0x00000000, LENGTH = 0x00800000
ram(!rx) : ORIGIN = 0x40000000, LENGTH = 0x00800000
h : ORIGIN = 0x40000000, LENGTH = 0x00400000
}
SECTIONS
{
.text : { *(.text*) } > rom
.bss : { *(.bss*) } > ram
.heap : { *(.heap*) } > h
}
end = ORIGIN(h) + LENGTH(h);
_stacktop = ORIGIN(ram) + LENGTH(ram);
Your build linker script (normally a .ld file) determines the locations of your device's memory and how the linker sections are mapped to that. Your link map should not include writable sections in read-only memory, that will fail.
[Added after linker script added to question]
You linker script seems unusual in lacking a .data section:
.data : { *(.data) } > ram
Without that it is not clear what the linker will do with static initialised data.
Also your question states that the RAM starts at 0x800000, but the linker script clearly locates it at 0x40000000. Perhaps this misunderstanding of your memory map is leading you to erroneously believe that writes to the ROM region are occurring?

Stack allocation to process and its occupancy by the data segment

Sorry if the questions are dumb, but they are really confusing me!
According to elf standard the binary is divided into segments like text segment (containing code and RO data) and data segment (containing RW & BSS) which is loaded into memory when the program is executed and process is created, with the segments providing information for environment preparation for process execution.
The question is, how it is decided that how much stack to allocate to process, when i am not providing stack size during process creation?
Also, using the data segment we can determine how much memory the process requires (for global variables) but once this memory is allocated how mapping of variables is done with the address space inside this allocated memory?
Lastly, is there any relation of this with scatter loading? which i think is not the case as scatter loading is done when image is to be loaded into memory and once control is passed to OS, the memory to be allocated to executable or applications is take care off by the OS itself!
I know these are too many questions, but any help will be greatly appreciated.
If u can provide any reference books or links where i can study in detail about this, that is also appreciated.
Thanks a tonne! :)
The question is, how it is decided that how much stack to allocate to process, when i am not providing stack size during process creation?
When a new process created, execve() system call is used to load the new program as process image into memory from the current running process image. Which mean execve when new program is loaded replaces older .text, .data segments, heap and reset the stack. Now ELF executable file is mapped into memory address space making stack space getting initialized with environment array and the argument array to main().
In do_execve_common() procedure call under subroutine bprm_mm_init() handles tasks such as,
New instance of mm_struct to manage process address space using call to mm_alloc().
Initialize this instance with init_new_context().
bprm_mm_init() initializes stack.
search_binary_handler() routine searches for suitable binary format i.e load_binary, load_shlib to load programs or dynamic libraries respectively. Followed by mapping memory to virtual address space and making process ready to run when scheduler identifies the process.
Therefore, stack memory finally looks like below, which will appear to main() routine at start of the execution. Now and then each environment of a subset of function calls, including parameters and local variables are stored or pushed in stack memory zone dynamically when the calls happen.
-----------------
| | <--- Top of the Stack
| environmental |
| variables and |
| the other |
| parameters to |
| main() |
_________________ <--- Stack Pointer
| |
| Stack Space |
| |
Also, using the data segment we can determine how much memory the process requires (for global variables) but once this memory is allocated how mapping of variables is done with the address space inside this allocated memory?
Let try figuring out how variables are mapped to different parts of memory segments by debugging a simple C program as follows,
/* File Name: elf.c : Demonstrating Global variables */
#include <stdio.h>
int add_numbers(void);
int value1 = 10; // Global Initialized: .data section
int value2; // Global Initialized: .bss section
int add_numbers(void)
{
int result; // Local Uninitialized: Stack section
result = value1 + value2;
return result;
}
int main(void)
{
int final_result; // Local Uninitialized: Stack section
value2 = 20;
final_result = add_numbers();
printf("The sum of %d + %d is %d\n",
value1, value2, final_result);
}
Using readelf to display .data section header as below,
$readelf -a elf
...
Section Headers:
[26] .data PROGBITS 00000000006c2060 000c2060
00000000000016b0 0000000000000000 WA 0 0 32
[27] .bss NOBITS 00000000006c3720 000c3710
0000000000002bc8 0000000000000000 WA 0 0 32
...
$readelf -x 26 elf
Hex dump of section '.data':
0x006c2060 00000000 00000000 00000000 00000000 ................
0x006c2070 0a000000 00000000 00000000 00000000 ................
...
Let's use GDB to look at what these section contain,
(gdb) disassemble 0x006c2060
Dump of assembler code for function `data_start`:
0x00000000006c2060 <+0>: add %al,(%rax)
0x00000000006c2062 <+2>: add %al,(%rax)
0x00000000006c2064 <+4>: add %al,(%rax)
0x00000000006c2066 <+6>: add %al,(%rax)
End of assembler dump.
The above first address of .data section refers to data_start subroutine.
(gdb) disassemble 0x006c2070
Dump of assembler code for function `value1`:
0x00000000006c2070 <+0>: or (%rax),%al
0x00000000006c2072 <+2>: add %al,(%rax)
End of assembler dump.
....
The above disassemble dumps address of global variable value1 initialized to
10. But we don't see global uninitialized variable value2 in next addresses.
Let's look at printing the address of value2,
(gdb) p &value2
$1 = (int *) 0x6c5eb0
(gdb) info symbol 0x6c5eb0
value2 in section **.bss**
(gdb) disassemble 0x6c5eb0
Dump of assembler code for function `value2`:
0x00000000006c5eb0 <+0>: add %al,(%rax)
0x00000000006c5eb2 <+2>: add %al,(%rax)
End of assembler dump.
Tada! Disassembling reference pointer of value2 revels that the variable is stored in .bss section. This explains how the uninitialized global variables mapped to process memory space.
Lastly, is there any relation of this with scatter loading?
No.

Why does COW mmap fail with ENOMEM on (sparse) files larger than 4GB?

This happens on a 2.6.26-2-amd64 Linux kernel when trying to mmap a 5GB file with copy-on-write semantics ( PROT_READ | PROT_WRITE and MAP_PRIVATE). Mapping files smaller than 4GB or using only PROT_READ works fine. This is not a soft resource limit issue as reported in this question; the virtual limit size is unlimited.
Here is the code that reproduces the problem (the actual code is part of Boost.Interprocess).
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
main()
{
struct stat b;
void *base;
int fd = open("foo.bin", O_RDWR);
fstat(fd, &b);
base = mmap(0, b.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (base == MAP_FAILED) {
perror("mmap");
return 1;
}
return 0;
}
and here is what happens:
dd if=/dev/zero of=foo.bin bs=1M seek=5000 count=1
./test-mmap
mmap: Cannot allocate memory
Here is the relevant strace (freshly compiled 4.5.20) output, as asked by nos.
open("foo.bin", O_RDWR) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=5243928576, ...}) = 0
mmap(NULL, 5243928576, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = -1 ENOMEM (Cannot allocate memory)
dup(2) = 4
[...]
write(4, "mmap: Cannot allocate memory\n", 29mmap: Cannot allocate memory
) = 29
Try passing MAP_NORESERVE in the flags field like this:
mmap(NULL, b.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_NORESERVE, fd, 0);
It's likely the combination of your swap and physical memory are less than the 5GB requested.
Alternatively you can do this for testing purposes, if it works, you can make the code change above:
# echo 0 > /proc/sys/vm/overcommit_memory
Below are the relevant extracts from the manual pages.
mmap(2):
MAP_NORESERVE
Do not reserve swap space for this mapping. When swap space is
reserved, one has the guarantee that it is possible to modify
the mapping. When swap space is not reserved one might get
SIGSEGV upon a write if no physical memory is available. See
also the discussion of the file /proc/sys/vm/overcommit_memory
in proc(5). In kernels before 2.6, this flag only had effect
for private writable mappings.
proc(5):
/proc/sys/vm/overcommit_memory
This file contains the kernel virtual memory accounting mode.
Values are:
0: heuristic overcommit (this is the default)
1: always overcommit, never check
2: always check, never overcommit
In mode 0, calls of mmap(2) with MAP_NORESERVE are not checked,
and the default check is very weak, leading to the risk of get‐
ting a process "OOM-killed". Under Linux 2.4 any non-zero value
implies mode 1. In mode 2 (available since Linux 2.6), the
total virtual address space on the system is limited to (SS +
RAM*(r/100)), where SS is the size of the swap space, and RAM is
the size of the physical memory, and r is the contents of the
file /proc/sys/vm/overcommit_ratio.
Quoting your memory, swap size and overcommit settings from your comment:
MemTotal: 4063428 kB SwapTotal: 514072 kB
$ cat /proc/sys/vm/overcommit_memory
0
$ cat /proc/sys/vm/overcommit_ratio
50
With overcommit_memory set to 0 ("heuristic overcommit"), you can't create a private, writeable mapping that's larger than the current free memory and swap total - clearly, since you only have 4.5GB of memory + swap, that can never be true.
Your options are either to use MAP_NORESERVE (as Matt Joiner suggests), if you're sure that you'll never dirty (write to) more pages in the mapping than you have free memory and swap for; or to significantly increase the size of your swap space.

Resources