Los Frijoles
Los Frijoles

Reputation: 4821

Why does objcopy exclude one section but not another?

Background

I'm attempting to utilize a special section of SRAM on my STM32 device which is located at address 0x40006000. One way of doing this which I saw in ST's example code was just to simply create pointers whose value happened to live inside that section of RAM. What I'm trying to do is get the linker to manage static allocations in that section for me.

Basically, I'm going from something like this:

static uint16_t *buffer0 = ((uint16_t *)0x40006000);
static uint16_t *buffer1 = ((uint16_t *)0x40006080);

To something like this (which I think is far less breakable and not as hacky, though not as portable):

#define _PMA __attribute__((section(".pma"), aligned(2)))
static uint16_t _PMA buffer0[64];
static uint16_t _PMA buffer1[64];

In order to accomplish this, I've modified my linker script to have a new memory called "PMA" located at 0x40006000 and I have located the ".pma" section inside it as follows:

MEMORY
{
    FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
    RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
    PMA (xrw) : ORIGIN = 0x40006000, LENGTH = 1024 /* This is the memory I added */
}

SECTIONS
{
    .text
    {
        ..blah blah blah..
    } > FLASH

    ...more sections, like rodata and init_array..

    /* Initialized data goes into RAM, load LMA copy after code */
    .data
    {
        ..blah blah blah with some linker symbols to denote the start and end..
    } >RAM AT> FLASH

    .bss
    {
        ..blah blah blah..
    } >RAM

    .pma /* My new section! */
    {
        _pma_start = .;
        . = ALIGN(2);
        *(.pma)
        *(.pma*)
    } >PMA
}

What Happens

So this seems all fine and dandy, my stuff compiles and the map shows me that buffer0 and buffer1 are indeed placed at 0x40006000 and 0x40006080. Here is the output of the last bit of my makefile:

arm-none-eabi-gcc obj/usb_desc.o obj/usb_application.o obj/osc.o obj/usb.o obj/main.o obj/system_stm32f1xx.o obj/queue.o obj/list.o obj/heap_1.o obj/port.o obj/tasks.o obj/timers.o obj/startup_stm32f103x6.o -TSTM32F103X8_FLASH.ld -mthumb -mcpu=cortex-m3 --specs=nosys.specs -Wl,-Map,bin/blink.map -o bin/blink.elf
arm-none-eabi-objdump -D bin/blink.elf > bin/blink.lst
arm-none-eabi-size --format=SysV bin/blink.elf
bin/blink.elf  :
section              size         addr
.isr_vector           268    134217728
.text               13504    134218000
.rodata                44    134231504
.ARM                    8    134231548
.init_array             8    134231556
.fini_array             4    134231564
.data                1264    536870912
.jcr                    4    536872176
.bss                 1348    536872180
._user_heap_stack    1536    536873528
.pma                  256   1073766400
.ARM.attributes        41            0
.debug_info         26748            0
.debug_abbrev        5331            0
.debug_aranges        368            0
.debug_line          5274            0
.debug_str           8123            0
.comment               29            0
.debug_frame         4988            0
Total               69146


arm-none-eabi-objcopy -R .stack -O binary bin/blink.elf bin/blink.bin

I see that .pma has 256 bytes used, just as I expected. The address looks correct as well. Now, when I ls the bin directory I'm greeted by this:

-rwxr-xr-x 1 kevin users 939548800 Nov  2 00:04 blink.bin*
-rwxr-xr-x 1 kevin users    221528 Nov  2 00:04 blink.elf*

That bin file is what I'm loading onto my chip's flash via openocd. It is an image of the flash starting at 0x08000000.

Sidenote: I actually attempted to load that bin file onto my chip before I had realized how huge it was...that didn't work obviously.

Here's what I get when I remove the PMA section:

arm-none-eabi-size --format=SysV bin/blink.elf
bin/blink.elf  :
section              size        addr
.isr_vector           268   134217728
.text               13504   134218000
.rodata                44   134231504
.ARM                    8   134231548
.init_array             8   134231556
.fini_array             4   134231564
.data                1392   536870912
.jcr                    4   536872304
.bss                 1348   536872308
._user_heap_stack    1536   536873656
.ARM.attributes        41           0
.debug_info         26748           0
.debug_abbrev        5331           0
.debug_aranges        368           0
.debug_line          5274           0
.debug_str           8123           0
.comment               29           0
.debug_frame         4988           0
Total               69018

And the file size is exactly as I would expect:

-rwxr-xr-x 1 kevin users  15236 Nov  2 00:09 blink.bin
-rwxr-xr-x 1 kevin users 198132 Nov  2 00:09 blink.elf

Question

As I understand it, what is going on here is that objcopy has just copied everything from 0x08000000 to 0x400060FF into that bin file. That is obviously not what I wanted to happen. I expected that it would just copy the flash.

Now, obviously I can just say -R .pma on my objcopy command and everything will be happy. However, what I'm curious about is how objcopy knows not to copy .data into the binary image. I noticed that running objcopy -R .data has the exact same result as running objcopy without that. Same thing with .bss. This tells me that it isn't the AT command in the linker script (which is the only real difference I can see between .data and .bss)

What can I do to make my .pma section behave the same way as .data or .bss from objcopy's perspective? Is there something interesting going on with .data/.bss in the intermediate elf file I'm using perhaps (see above for the linker command generating the elf file)?

Upvotes: 2

Views: 2141

Answers (1)

guest1109
guest1109

Reputation: 11

Having defined your section as ".pma" most probably gave it the type "PROGBITS" (check with readelf), which indicates a section to be loaded on the target.

What you want/need is to define a section that doesn't have to be loaded on the target, like the ".bss" section, which has the type "NOBITS".

I frequently use the following section definition to avoid having certain buffers into the ".bss" section (as this slows down the startup phase due to the zero-initalization of the ".bss" section):

static uint8_t uart1_buffer_rx[4096] __attribute__((section(".noinit,\"aw\",%nobits@")));

I don't remember why I used the name ".noinit", but this sections appears after the ".bss" section.

In your case, it will probably help to add the "aw" and "nobits" flags after the ".pma" section declaration.

Upvotes: 1

Related Questions