How to allocate a variable at a given absolute address in memory (with GCC) - Page 1
Forum section: electronics / general

author: legacy
author_rank: Super Contributor
timestamp: January 16, 2016, 12:49:46 pm
content: Code:typedef struct{…} myData_t;export myData_t myData;ProblemsG/AS has a completely different implementation about dot org, if you happen to be good at low level programming, then, within { Microsoft/PC, Motorola/Freescale, IBM/PC }, you can appreciate that GNU dot org simply does different thingsG/CC does not support the following (even if they are used by clever compilers, including Green Hills, ADB and Keil)Code:/** Not Working, Not Supported by G/CC** myData_t myData _at_ myData_ADDR;* myData_t myData @ myData_ADDR;* myData_t myData __attribute__((at(myData_ADDR)));*/".org" does not work as expected from Motorola ASCode:/** Not working with G/AS*/.section .data.globl myData.org 0x90000000myData:.size myData, myData_SIZE.zero myData_SIZE // fill with 0x00The ".org 0xXXXX" directive at the beginning actually says:move the location counter from 0xYYYY to 0xXXXXpad the in-between area with 0x00s <---- evil, troubles come, if used, one will be reported a large block being copiededit:title changed into "allocate"

author: legacy
author_rank: Super Contributor
timestamp: January 16, 2016, 12:58:33 pm
content: memory begins at 0x9000.0000, so I modified the linker script.section .data begins now at 0x9000.0000 + sizeof(my_data_t), say size=0x200, it begins at 0x9000.0200in this way I can allocate with a trickmydata.sCode:.section .data.globl myData.set myData, 0x90000000mydata.hCode:typedef struct{uint8_t data;} myData_t;public myData_t myData;Code:0x9000.0000 mydata0x9000.01xx ..0x9000.0200 section dataideas ? advices ?

author: Kalvin
author_rank: Super Contributor
timestamp: January 16, 2016, 01:07:02 pm
content: Or you can use a constant pointer to access the data.

author: Kalvin
author_rank: Super Contributor
timestamp: January 16, 2016, 01:21:47 pm
content: Here is one discussion:http://stackoverflow.com/questions/4067811/how-to-place-a-variable-at-a-given-absolute-address-in-memory-with-gcc

author: legacy
author_rank: Super Contributor
timestamp: January 16, 2016, 01:26:15 pm
content: Quote from: Kalvin on January 16, 2016, 01:07:02 pmthis does't allocate the variable, I mean, I still need to use a part of the above ugly trickmore specifically: I still need to set the beginning of .section .data to 0x9000.0200

author: legacy
author_rank: Super Contributor
timestamp: January 16, 2016, 01:27:26 pm
content: Quote from: Kalvin on January 16, 2016, 01:21:47 pmI am able to use google, I'd like to hear your opinions, guys

author: Kalvin
author_rank: Super Contributor
timestamp: January 16, 2016, 01:37:11 pm
content: Quote from: legacy on January 16, 2016, 01:27:26 pmMy opinion: Using a linker script with sections attributes seems to be most portable way allocate a variable at the specific memory address.

author: Mechatrommer
author_rank: Super Contributor
timestamp: January 16, 2016, 02:23:11 pm
content: Quote from: Kalvin on January 16, 2016, 01:37:11 pmi agree but i also believe this is the devil details of C/C++ where portability rule breaks, where giant conditional #ifdefined branches is needed...since the op mentioned __attribute__(at(**)) didnt work, the target hardware may not be supporting it. he may try different variant specific to the hardware he's using. for eg, i saw different variant for avr chip where __attribute__(io(**)) is used... but other hardwares are not supporting the syntax...https://gcc.gnu.org/onlinedocs/gcc/AVR-Variable-Attributes.html#AVR-Variable-Attributesfrom...https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html#Variable-Attributeswhich turned out from...http://lmgtfy.com/?q=how+to+gcc+variable+specific+location

author: nctnico
author_rank: Super Contributor
timestamp: January 16, 2016, 02:31:03 pm
content: I always create a section in the link file and put the variables and/or functions in that section using the attribute keyword.

author: legacy
author_rank: Super Contributor
timestamp: January 16, 2016, 02:44:18 pm
content: so, something like:adding a special section ".my" into the linker scriptredefining borders of data section in linker script (now it begins down of 0x200 byte)using: myData_t volatile myData __attribute__((section (".my"))) __attribute__((aligned (32)));

author: Jeroen3
author_rank: Super Contributor
timestamp: January 16, 2016, 03:32:23 pm
content: Option 1:-Put your variables/arrays in a separate myData.C file. Add const or volatile as you see fit. For flash, you'd need const. For peripherals, you'd need volatile.-Create a header file with extern declarations to use them elsewhere in the code.-Tell the linker that your want myData.o in a specific region.Option 2:- Tell the linker to create an empty region, or simply don't tell the linker to use the region exists all.- Use (#defined) pointers to create a method of accessing the region. Also be aware if you need const and volatile depending on the memory location and expected behavior.This is how you access peripheral registers. See your "mymcu.h" file where the registers are defined what you need to do for the pointer part.

author: AndyC_772
author_rank: Super Contributor
timestamp: January 16, 2016, 03:35:34 pm
content: I'd go with creating extra sections in the linker script. Normally I don't care so much that a variable goes in a very particular location, but that it goes somewhere within a section that's treated differently to "normal" RAM space. More often than not, there are several variables which need each kind of special treatment, and I don't want to have to specify each address individually.I might, for example, have sections which are:- "normal"- not initialised to zero on reboot- periodically copied to Flash, and restored at power up- write protected- included within a checksum- used for message passing between bootloader and application... and so on.

author: legacy
author_rank: Super Contributor
timestamp: January 16, 2016, 03:47:31 pm
content: Quote from: Jeroen3 on January 16, 2016, 03:32:23 pmthat is what I have written above

author: legacy
author_rank: Super Contributor
timestamp: January 16, 2016, 03:51:44 pm
content: Code:memory space:0x9000.0000 section data0x9000.01xx ..0x9000.02xx ..beforeCode:memory space:0x9000.0000 section my <--- mydata, size=0x2000x9000.01xx ..0x9000.0200 section dataaftermyData.SCode:.section .data.data.globl myData.set myData, 0x9000000.set size, 0x200myData.hCode:typedef struct{uint32_t data;} volatile my_Data_t;public my_Data_t my_Data;myData.cCode:#include "mydata.h"my_Data_t my_Data;

author: legacy
author_rank: Super Contributor
timestamp: January 16, 2016, 03:57:08 pm
content: Code:#define DataRegister_ADDR 0x90000000typedef struct{…} myData_t;typedef myData_t* p_myRegister_t;p_Data_t volatile p_Data = (p_Data_t) (Data_ADDR);but I do not like, too much

author: andyturk
author_rank: Frequent Contributor
timestamp: January 16, 2016, 04:16:05 pm
content: I'd much rather put specific location info in C/C++ source than burying it in the linker file. I've done it both ways, but explaining to your team that critical information lives in a strange file that most of them have never seen before is not ideal. Usually, the placement of these variables is important, and requires documentation. Put that doc in the linker file too?Plus, if you're talking about peripheral registers, you'll probably end up having lots of those and the locations won't be contiguous. That means you'll need to have lots of symbols exported from the linker. Put that stuff in normal source code! Here's how I do it (in C++):Code:struct MyPeripheral {uint32_t foo;uint32_t bar;...};// my_periph is a machine register. see page 1234 of the datasheetvolatile MyPeripheral& my_periph {*reinterpret_cast<MyPeripheral *>(0x90000000)};

author: ale500
author_rank: Frequent Contributor
timestamp: January 16, 2016, 04:19:41 pm
content: In your linker script you define a section at the right physical address with the right size. In the code you assign the variable(s) to the section with the __atribute__ attributeCode:int8_t schwarzes_pixel __attribute__ ((section (".lram128k")))=0; // für DMACode:MEMORY{FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024KRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64KLRAM128K(xrw) : ORIGIN = 0x20000000, LENGTH = 128KMEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K}.../* LRAM128K section, data must be located here explicitly *//* Example: extern int array __attribute__ ((section (".lram128k"))); */.memory_b1_text :{*(.lram128k) /* data */} >LRAM128KMap file says:Code:.memory_b1_text0x0000000020000000 0x1fa6c*(.mb1text)*(.mb1text*)*(.mb1rodata)*(.mb1rodata*)*(.lram128k).lram128k 0x0000000020000000 0x1fa6c cce0b7ns.ltrans0.ltrans.oThere are ways to specify the location in the source file using for instance #pragma but that is very compiler specific and not portable. I've been burned by those because the better (expected) way is in the linker file.

author: rsjsouza
author_rank: Super Contributor
timestamp: January 16, 2016, 04:22:20 pm
content: I haven't seen a way to allocate data at specific addresses without using either an implementation-specific feature or, in case of GCC and some specific compilers, without modifying the linker script. I particularly think the linker approach is more elegant.

author: Kalvin
author_rank: Super Contributor
timestamp: January 16, 2016, 04:22:38 pm
content: You can also add a comment pointing to the linker file into the source code where you declare the external variable. Then the reader understands to peek into the linker file for more specific information like the absolute address etc. if needed.

author: bson
author_rank: Unknown
timestamp: January 16, 2016, 09:45:51 pm
content: Quote from: andyturk on January 16, 2016, 04:16:05 pmThis is how I do it too - the address still has to be stored someplace, even if an immediate inline constant in the instruction stream. So it needs to be fetched since the peripheral space can't be relative addressed, no matter what. Using a C++ reference here is important, because it tells the compiler it can't be changed after assignment (initialization) so is effectively a constant pointer (not to be confused with pointer-to-const) within its scope. The volatile of course refers to the referenced, not the reference. Without proper care or casual use of C pointers (not C++ references) easily results in excessive loading of the base address and the compiler can't treat it as a constant and can't move it out of loops. It can even prevent proper inlining.

author: miguelvp
author_rank: Super Contributor
timestamp: January 17, 2016, 02:52:50 am
content: In my ongoing PSoC tutorial I needed my DMA frame buffer at a specific place so I did the following:Used the following flags to declare a section:-Wl,--section-start=.ram2=0x20000000Then use it as this:uint8 dframe __attribute__ ((aligned(),section(".ram2")));But the proper way is to declare the section in the custom linker file then use the section the same way so other sections don't overlap.Since I know and I'm monitoring the compile report out I didn't bother.https://www.eevblog.com/forum/projects/no-bitbanging-necessary-or-how-to-drive-a-vga-monitor-on-a-psoc-5lp-programmabl/msg825368/#msg825368

author: westfw
author_rank: Super Contributor
timestamp: January 17, 2016, 06:04:09 am
content: With the gnu tools, positioning code or data at particular addresses is done during link, rather than during compile.You can use separate sections for "special" segments, combined either with a mysterious custom linker map, or a link command with mysterious --section-start options.Macros are recommended (IMO) in the C code, for portability's sake:Code:uint8 RAM2VAR(dframe);rather thanuint8 dframe __attribute__ ((aligned(),section(".ram2")));

author: miguelvp
author_rank: Super Contributor
timestamp: January 17, 2016, 06:24:45 am
content: Quote from: westfw on January 17, 2016, 06:04:09 amThis will never be portable, the PSoC5LP has two separate 32KB buffers, one at the end of the code space and the other at the beginning of the sram space.The buffer in question is accessible by a DMA channel that sends the bytes to be displayed in the screen, if it was on the same section as the buffer where the CPU writes the buffer then there would be memory contention and that would be displayed in the screen. Actually just accessing any variable in the code space will stall that DMA transfer.While that DMA channel accesses the separate upper 32KB buffer the CPU is free to fill the lower 32KB buffer and/or use variables that reside in the code memory space.At the end of the DMA buffer to screen and during the vertical sync, a 2nd DMA is used to copy the CPU buffer to the DMA buffer.As for a macro, well I would have to define it then, but since that's a tutorial for that specific hardware and not portable at all, then I rather leave it explicitly coded for clarity on where that buffer resides.If I was to actually polish it, I would use the mysterious custom linker scripts and reducing the .ram section to 32KBNot sure why they are so mysterious but to each their ownEdit: Plus I was answering the OP question on how to place a variable at a given absolute address in memory (with GCC)Edit: If he was using keil I would have said to use _at_ but he already knew that.Edit: BTW my .map reports the following:.ram2 0x20000000 0x7530.ram2 0x20000000 0x7530 .\CortexM3\ARM_GCC_493\Debug\main.o0x20000000 dframefor the 30,000 byte DMA buffer.

author: westfw
author_rank: Super Contributor
timestamp: January 17, 2016, 08:05:11 am
content: If it's a single buffer, you might as well write a special "malloc" function that returns a cast constant, and modify the linker script just so that it knows it can't use that memory any more.

author: miguelvp
author_rank: Super Contributor
timestamp: January 17, 2016, 08:16:56 am
content: Not the point, the OP might want to have more than one absolute address, maybe memory mapped I/O ports? don't know.He could add as many sections of many lengths on specific addresses on the linker script and declare them in code accordingly.In my case this was the easiest way for such a long write-up, where I want to focus into the task at hand.I mean: 800x600@60Hz with 60fps update time (every 16.666ms) from the CPU on a small Cortex M3 MCU with at least at least 636,942.7 CPU cycles (or 15.924 ms) per frame left to modify that buffer for buttery smooth graphics, why would I want non portable special mallocs when I can do non portable memory sections?Specially since the frame buffers eat up 60,000 bytes out of the 64KB SRAM? Not that matters because I have plenty of program space on the Flash Ram, but anyways.Took the shorter route to get the point across after a humongous amount of documenting the steps, don't really need more steps

author: legacy
author_rank: Super Contributor
timestamp: January 17, 2016, 09:41:35 am
content: Quote from: miguelvp on January 17, 2016, 08:16:56 amops, I had forgotten to say: yesedit: yes, I also need them

author: bson
author_rank: Unknown
timestamp: January 17, 2016, 11:43:59 pm
content: You can of course declare symbols extern volatile in your code, then define them in the linker script. Kind of cumbersome though.

author: Lukas
author_rank: Frequent Contributor
timestamp: January 18, 2016, 01:07:34 am
content: Quote from: legacy on January 17, 2016, 09:41:35 amOk, then you don't need all the section funny business :Code:#define myData ((myData_t *) 0xbabaf001)That's how people do in the ARM header files.

author: westfw
author_rank: Super Contributor
timestamp: January 18, 2016, 05:49:26 am
content: QuoteMicrochip is (was?) defining peripheral base addresses at link time for PIC32, rather than the more common constant pointers in .h files.It made for some interesting "missed optimizations." IIRC, they claim this does a better job at making binary-distribution libraries possible.

author: legacy
author_rank: Super Contributor
timestamp: January 18, 2016, 10:09:49 am
content: Quote from: Lukas on January 18, 2016, 01:07:34 amI need it when I need toallocatevariables which have to be used in shared ram, my project has both these two needsI/O(e.g. a quadri port lan, each port is memory mapped, but the whole device is mapped into a special section called IO_ports, so it's not memory, even if handled as memory, e.g. load/store instruction, without cache), I prefer to have symbols defined in assembly, called BSP_IO.S, their interfaces are declared in BSP_IO.h, while BSP_IO.c defines IO_methodsshared ram, shared between two CPUs, it comes with things that must stay at a given absolute address in memory, I like the linker script method, but I'd rather use a special trick: I have defined symbols in BSP_shared_ram.S (say "absolute addresses", which are known since the beginning, it's good from the documentation point of view), their interface (and sizes) in BSP_shared_ram.h, and their implementation in BSP_shared_ram.cedit:I am also going to implement the other approach (pure linker script) in order to compare them from the "error prone" point of view

author: legacy
author_rank: Super Contributor
timestamp: January 18, 2016, 10:11:32 am
content: Quote from: westfw on January 17, 2016, 08:05:11 amthat looks nice for my SMP project, nice idea