Can GNU LD print memory usage by memory space, rather then just as a bulk percentage? - c

I'm working on an embedded project on an ARM mcu that has a custom linker file with several different memory spaces:
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00200000
data_tcm (rw) : ORIGIN = 0x20000000, LENGTH = 0x00008000
prog_tcm (rwx) : ORIGIN = 0x00000000, LENGTH = 0x00008000
ram (rwx) : ORIGIN = 0x20400000, LENGTH = 0x00050000
sdram (rw) : ORIGIN = 0x70000000, LENGTH = 0x00200000
}
Specifically, I have a number of different memory devices with different characteristics (TCM, plain RAM (with a D-Cache in the way), and an external SDRAM), all mapped as part of the same address space.
I'm specifically placing different variables in the different memory spaces, depending on the requirements (am I DMA'ing into it, do I have cache-coherence issues, do I expect to overflow the D-cache, etc...).
If I exceed any one of the sections, I get a linker error. However, unless I do so, the linker only prints the memory usage as bulk percentage:
Program Memory Usage : 33608 bytes 1.6 % Full
Data Memory Usage : 2267792 bytes 91.1 % Full
Given that I have 3 actively used memory spaces, and I know for a fact that I'm using 100% of one of them (the SDRAM), it's kind of a useless output.
Is there any way to make the linker output the percentage of use for each memory space individually? Right now, I have to manually open the .map file, search for the section header, and then manually subtract the size from the total available memory specified in the .ld file.
While this is kind of a minor thing, it'd sure be nice to just have the linker do:
Program Memory Usage : 33608 bytes 1.6 % Full
Data Memory Usage : 2267792 bytes 91.1 % Full
data_dtcm : xxx bytes xx % Full
ram : xxx bytes xx % Full
sdram : xxx bytes xx % Full
This is with GCC-ARM, and therefore GCC-LD.

Arrrgh, so of course, I find the answer right after asking the question:
--print-memory-usage
Used as -Wl,--print-memory-usage, you get the following:
Memory region Used Size Region Size %age Used
rom: 31284 B 2 MB 1.49%
data_tcm: 26224 B 32 KB 80.03%
prog_tcm: 0 GB 32 KB 0.00%
ram: 146744 B 320 KB 44.78%
sdram: 2 MB 2 MB 100.00%

Related

Linker with overlapping memory definitions

I made an ld script with the following memory layout:
MEMORY
{
FLASH (rx) : ORIGIN = 0x00027000, LENGTH = 0xC8000
RAM (rwx) : ORIGIN = 0x20003FC0, LENGTH = 0x3B040
RRAM (rwx) : ORIGIN = 0x2000F000, LENGTH = 0x01000
}
As you can see, the RRAM (from 0x2000F000 to 0x2000FFFF) portion overlaps with the RAM portion (from 0x20003FC0 to 0x2002FFF). The code compiles and links with no warnings or errors.
My question is: during normal code execution,.will the system still be able to use the memory from 0x2001000 up to 0x2002FFF? Or does this unusual layout stop the code from using anything after the end of RRAM (unless explicitly allocated to an address)?

Retroarch Memory Map undefined for PSX (Beetle PSX HW)

I am working on pulling data from Retroarch via JSON format using software called Gamehook.
I am trying to add support for the PSX with the Beetle PSX HW core.
The issue is that even with extensive searching through the core and retroarch's source code, I cannot find a proper memory map for it. I have tried adding the ranges from the two sources below, which gives me a "no memory map defined" error.
http://www.raphnet.net/electronique/psx_adaptor/Playstation.txt
0x8000_0000 0x801f_ffff Kernel and User Memory Mirror (2 Meg) Cached
0xa000_0000 0xa01f_ffff Kernel and User Memory Mirror (2 Meg) Uncached
0x0000_0000-0x0000_ffff Kernel (64K)
0x0001_0000 0x001f_ffff User Memory (1.9 Meg)
0x1f80_0000-0x1f80_03ff Scratch Pad (1024 bytes)
and
https://psx-spx.consoledev.net/memorymap/
KUSEG KSEG0 KSEG1
00000000h 80000000h A0000000h 2048K Main RAM (first 64K reserved for BIOS)
1F000000h 9F000000h BF000000h 8192K Expansion Region 1 (ROM/RAM)
1F800000h 9F800000h -- 1K Scratchpad (D-Cache used as Fast RAM)
1F801000h 9F801000h BF801000h 8K I/O Ports
1F802000h 9F802000h BF802000h 8K Expansion Region 2 (I/O Ports)
1FA00000h 9FA00000h BFA00000h 2048K Expansion Region 3 (SRAM BIOS region for DTL cards)
1FC00000h 9FC00000h BFC00000h 512K BIOS ROM (Kernel) (4096K max)
FFFE0000h (in KSEG2) 0.5K Internal CPU control registers (Cache Control)
Looking at consoleinfo.c in the Retroarch source code, it defines the memory regions for Playstation as.
/* ===== PlayStation ===== */
/* http://www.raphnet.net/electronique/psx_adaptor/Playstation.txt */
static const rc_memory_region_t _rc_memory_regions_playstation[] = {
{ 0x000000U, 0x00FFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Kernel RAM" },
{ 0x010000U, 0x1FFFFFU, 0x010000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
};
static const rc_memory_regions_t rc_memory_regions_playstation = { _rc_memory_regions_playstation, 2 };
And the definition for rc_memory_region_t is
typedef struct rc_memory_region_t {
unsigned start_address; /* first address of block as queried by RetroAchievements */
unsigned end_address; /* last address of block as queried by RetroAchievements */
unsigned real_address; /* real address for first address of block */
char type; /* RC_MEMORY_TYPE_ for block */
const char* description; /* short description of block */
}
rc_memory_region_t;
I have asked in the Retroarch discord server and they have unfortunately given me conflicting information. Such as, I want to use the RetroAcheievements memory address or that I need to find out how Retroarch deals with memory addressing of the cores.
With that second portion, I have looked at the entire source code in depth and have only found the memory addressing information here.
So my question comes down to, does anyone know either how to find the mappable memory addresses from the cores in Retroarch or does anyone happen to know the mappable memory addresses from the cores in Retroarch?

Is writing to a section not defined in linker file allowed?

In my linker file, I have the following memory sections.
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k
mram (rwx) : ORIGIN = 0xA0000010, LENGTH = 1M
}
The actual address of the mram peripheral starts at 0xA0000000. In a C file I can write to a specific memory address as
(*(uint32_t *)(void *)0xA0000000) = 0xaabbccdd;
Will this cause any problems?
The space specified in the linker script defines where and what the linker can locate in the defined memory regions. It will not locate anything to the "hole" you have left at 0xA0000000 to 0xA000000F because it is not aware of it.
In that sense it is "safe" in that the linker will not attempt to use that space. It is entirely in the control of your code - you have taken responsibility for that region by not giving it to the linker. And indeed the statement:
(*(uint32_t *)(void *)0xA0000000) = 0xaabbccdd;
will write a 32 bit value to that location. The point is neither the compiler nor the linker will prevent you from doing what you will in that region.
What is less plausible is LENGTH = 1M. That would make your mram 0x100010 bytes long (i.e. 1M + 0x10). That is a problem because the linker is free to locate objects in the region 0x100000 to 0x10000F. The consequences of that depend on your hardware, but quite possibly it will wrap into the region 0x100000 to 0x10000F that you have attempted to hide from the linker. I would imagine that you need LENGTH = 1M - 0x10 or LENGTH = 0x0FFFF0.
Now while you can absolve the linker from managing that region in order to manage it in your code, it may not be the best approach. It would be better to create a linker symbol at the required absolute address.
So given:
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k
mram (rwx) : ORIGIN = 0xA0000000, LENGTH = 1M
}
Your would create a linker symbol in mram:
SECTIONS
{
...
.mram :
{
reserved_mram = 0 ; /* address is zero offset from .mram1 */
. += 0x10 ; /* create 16 byte "hole" at address reserved_mram */
... /* other mram linker assignment follows */
} < mram
...
}
Then in your code you should be able to declare:
extern uint32_t reserved_mram[] ; // 4 x 32-bit word array.
And through reserved_mram you can access the memory at 0xA00000000 symbolically and the code is always in sync with the linker script so you can relocate the space easily without introducing a conflict.
Of course there is no bounds checking and no size information - you still need to confine your access to reserved_mram[0] to reserved_mram[3].
You might alternatively create a separate symbol for each location (with meaningful names specific to your application):
.mram :
{
reserved_mram1 = 0 ;
. += 4 ;
reserved_mram2 = . ;
. += 4 ;
reserved_mram3 = . ;
. += 4 ;
reserved_mram4 = . ;
. += 4 ;
... /* other mram linker usage follows */
} < mram
Then in your code:
extern uint32_t reserved_mram1 ;
extern uint32_t reserved_mram2 ;
extern uint32_t reserved_mram3 ;
extern uint32_t reserved_mram4 ;
Another alternative; you might create an independent section for the region, then create variables within it using __attribute__((section(.xxx))) directives in the code. e.g:
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k
mram1 (rwx) : ORIGIN = 0xA0000000, LENGTH = 0x10
mram2 (rwx) : ORIGIN = 0xA0000010, LENGTH = 0xFFFF0
}
SECTIONS
{
...
.mram1 :
{
*(.mram1)
} < mram1
...
}
Then in your code:
uint32_t my_mram_data __attribute__ ((section (".mram1"))) ;
The variable my_mram_data will be created somewhare in .mram1, but the linker decides where. The advantage here is that you can create arbitrary variables in the code without modifying the linker script, and if you attempt to allocate to .mram1 more data than is available you will get a linker error.
Note that linker script syntax is arcane and varies between linkers - I am unassuming this relates to the GNU linker? But my linker foo is strictly on demand (i.e. I figure it out when I need to) and I make no claim that any of the above is complete or correct, or even the only possible solutions - regard it as illustrative, and refer to the linker documentation for accurate information.

Get address of ram sections during runtime

I want to implement a stack usage monitor for my NRF52840-Mikrocontroller with Segger Embedded Studio.
To monitor the maximum stack usage, I need some information during runtime like the end address of the .bss segment, which is the start of my free memory.
My approach is, to fill the ram from the .tbss section until to the stackpointer with a magic word.
During runtime, the stack will grow and will overwrite my magic words with data.
In a cyclic check, I am able to dedicate the end of the stack. From that information, I can derive the approximate stack usage.
Is it possible to get the addresses from the picture below during runtime in my c (or ASM) Program?
Here is a part of my .map file, where for example the symbol __bss_start is defined. Is it possible to access this symbol from c code?
*(COMMON)
0x0000000020020ec4 __bss_end__ = (__bss_start__ + SIZEOF (.bss))
0x000000000001b8c8 __bss_size__ = SIZEOF (.bss)
0x0000000020020ec4 __bss_load_end__ = __bss_end__
0x0000000000000001 . = ASSERT (((__bss_start__ == __bss_end__) || ((__bss_end__ - __RAM_segment_start__) <= __RAM_segment_size__)), error: .bss is too large to fit in RAM memory segment)
0x0000000020020ec4 __tbss_load_start__ = ALIGN (__bss_end__, 0x4)
Thanks for your help, I have solved the Problem now.
To access the symbols of the .map file during runtime, I used the following code:
extern char __bss_end__;
int main()
{
char * bss = &__bss_end__;
}
After this line of code, the bss variable contains the start address of the bss-section.
With this code, I am able to get the addresses of the RAM segments during runtime to monitor my stack usage.

Align a variable in memory with offset from power of two in memory

I would like to place a 2kB chunk of memory, aligned 16 bytes before a 1024 bytes alignment.
Platform : arm, bare metal, GNU toolchain. No need for portability
Can I do that with either GCC/attributes pragmas, ld custom linker script or any other solution ?
I would like to avoid wasting 1kB for that (basically placing a 3kB chunk of memory aligned at 1kB & adding 1024-16 bytes of padding).
Forcing a particular address to place the data is possible, but will ld be able to place variables before and after it (or is it just a way to put padding ? )
Context : buffer needs to be at 1k boundary by hardware design , but I'd like to add a bit of room before / after to be able to copy to this buffer with no bounds checking if my source is at most 16B wide.
edit: added example.
Let's say I have RAM starting at 0x2000000. I need a char buf[2048] be placed in it, at 1024*N-16 offset - ie (&buf[16])%1024==0 , hopefully without losing 1008 padding bytes.
(edit2)
So I'd like to have :
0x2000000 - some vars
0x2000010 - some other vars ...
0x2000100 - some other vars ...
0x20003F0 - char buf[2048] : here (int)&buf[16]%1024=0x2000400%1024==0
0x2000BF0 - some other vars ...
ALIGN(exp) is equivalent to (. + exp - 1) & ~(exp - 1). Of course, that expression only works if exp is a power of two. So you can't use ALIGN(), but you can write your own expression that does produce the result you want. Something like ((. + 1024 + 16 - 1) & ~(1024 - 1)) - 16 should do the trick. Plug in various values for . and you see it rounds up like you want.
The problem you'll have is that the linker will place every section you specified to be before your special section before it, and every section specified to be after it after it. It won't cleverly order the .data sections of different files to be before or after so as to produce the minimum amount of padding. It also won't re-order individual variables within an object file and section at all. If you are trying to pack as tightly as possible, I think you'll need to do something like:
.data : {
*(.about1008bytes)
. = ((. + 1024 + 16 - 1) & ~(1024 - 1)) - 16
*(.DMAbuf)
*(.data)
}
Use a section attribute to place your buffer in .DMAbuf and try to find close to but not more than 1008 bytes of other data variables and stick them in section .about1008bytes.
If you want to go crazy, use gcc -fdata-sections to place every data object in its own section, extract the section sizes with readelf, give that to a program you write to sort them for optimal packing that then spits out a chunk of linker script listing them in the optimal order.
You should define a specific section into your linker script, with the required alignment.
Looking at the man
ALIGN(exp)
Return the result of the current location counter (.) aligned to the next exp boundary. exp must be an expression whose value is a power of two. This is equivalent to
(. + exp - 1) & ~(exp - 1)
ALIGN doesn't change the value of the location counter--it just does arithmetic on it. As an example, to align the output .data section to the next 0x2000 byte boundary after the preceding section and to set a variable within the section to the next 0x8000 boundary after the input sections:
SECTIONS{ ...
.data ALIGN(0x2000): {
*(.data)
variable = ALIGN(0x8000);
}
... }
The first use of ALIGN in this example specifies the location of a section because it is used as the optional start attribute of a section definition (see section Optional Section Attributes). The second use simply defines the value of a variable. The built-in NEXT is closely related to ALIGN.
As an example you can define your section
SECTIONS
{
.myBufBlock ALIGN(16) :
{
KEEP(*(.myBufSection))
} > m_data
}
and into your code you can
unsigned char __attribute__((section (".myBufSection"))) buf[2048];
EDIT
SECTIONS
{
.myBufBlock 0x0x7FBF0 :
{
KEEP(*(.myBufSection))
} > m_data
}
and into your code you can
unsigned char __attribute__((section (".myBufSection"))) buf[16+2048+16];
To your DMA you can set the address &buf[16] that will be 1k aligned.

Resources