I'm working on a Zynq Ultrascale+ MPSoC and trying to play around with the on and off chip memories. In the following program, I'm trying to place only variable 'x' into OCM (on-chip-memory) where everything else is loaded into external DDR.

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"

volatile u32 x __attribute__ ((section ("psu_ocm_ram_0_MEM_0"))) = 10;
volatile u32 *p = &x;

int main()

    xil_printf("x = %u\r\n", x);
    xil_printf("p = %p\r\n", p);

    return 0;

The output is:

x = 10
p = 2AB0

So it doesn't look like p is pointing to a variable in OCM memory according to the memory map below.

enter image description here

If I change to linker script to put the entire .data section into OCM (and get rid of the gcc attribute), then the output becomes as I expected:

x = 10
p = FFFC0130

The weird thing is that the .map file for the original program does show that the linker is trying to do something with the variable, I'm just not sure what:

                0x0000000000002ab0                __data_end = .

                0x0000000000002ab0        0x0
                0x0000000000002ab0        0x0 
                0x0000000000002ab0        0x0 

.igot.plt       0x0000000000002ab0        0x0
 .igot.plt      0x0000000000002ab0        0x0 

                0x0000000000002ab0        0x4
                0x0000000000002ab0        0x4 ./src/helloworld.o
                0x0000000000002ab0                x

So it looks like the variable is being placed at the end of the .data section, which is in DDR (for the original code), but I want the variable in OCM. Anybody know what's going on here?

  • 3
    \$\begingroup\$ Much as I hate plowing through lots of lines of code -- post your linker script (whatever.ld), or at least the part that defines memory sections. It looks like the __attribute__ part is working, but the linker is putting the segment in the wrong spot. \$\endgroup\$ – TimWescott May 14 '19 at 20:14
  • \$\begingroup\$ Your comment got me thinking I wasn't doing something properly with the linker script. Turns out I was trying to put the variable directly into OCM memory with the gcc variable attribute. I needed to create a custom section in the linker script, tell the linker that this section ought to live in OCM, then reference that section in the gcc variable attribute. All good now, thanks! \$\endgroup\$ – pr871 May 14 '19 at 20:49
  • 3
    \$\begingroup\$ If you can, take the time to answer your question yourself with a before & after snippet from the linker script (or maybe just "I added these lines in the ... section"). If you're asking, there's at least 100 other people out there wondering. \$\endgroup\$ – TimWescott May 14 '19 at 21:22
  • \$\begingroup\$ One of the 100, here.... \$\endgroup\$ – Curt Nichols May 14 '19 at 22:50
  • \$\begingroup\$ This looks like a screen shot from Crossworks? If so, there are ways to do this through an XML file rather than manually writing the linker script, though either way should work. \$\endgroup\$ – Lundin May 21 '19 at 14:48

It turns out I wasn't using the gcc attribute correctly. I was trying to place the variable directly into OCM using:

volatile u32 x __attribute__ ((section ("psu_ocm_ram_0_MEM_0"))) = 10;

as if the compiler is able to put individual variables into specific memory locations. Rather, it's the linker that's responsible for assigning all executable code (data and instructions) to physical memory. It order to make this work, I had to create a custom section in the linker script and assign this section to OCM:

.my_section : {
} > psu_ocm_ram_0_MEM_0

Then in my code:

volatile u32 x __attribute__ ((section (".my_section"))) = 10;

The output was then:

x = 10
p = FFFC0000

as expected.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.