rust-embedded/cortex-m-quickstart

Support for adding section

tiberiusferreira opened this issue · 16 comments

Hello,

I'm using the FRDM-KL25Z and it needs a "flash protection" section. I tried modifying the memory.x script as follows:

MEMORY
{
  VECTORS (rx) : ORIGIN = 0x00000000, LENGTH = 0x00000400
  FLASH_PROTECTION	(rx) : ORIGIN = 0x00000400, LENGTH = 0x00000010
  FLASH (rx) : ORIGIN = 0x00000410, LENGTH = 128K - 0x00000410
  RAM (rwx) : ORIGIN = 0x1FFFF0C0, LENGTH = 16K - 0xC0
}

SECTIONS
{
    .flash_protect :
    {
        KEEP(*(.flash_configuration))
         . = ALIGN(4);
    } > FLASH_PROTECTION

}

With the following data:

#[link_section=".flash_configuration"]
#[used]
static FLASH_CONFIG_FIELD: [u32; 4] = [
    0xFFFFFFFF,
    0xFFFFFFFF,
    0xFFFFFFFF,
    0xFFFFFFFE,
];

But after compiling and generating the .bin file, the address is not set.

screen shot 2018-04-02 at 13 54 53

I'm using the following commands to compile and generate the bin
xargo build --target thumbv6m-none-eabi --release -v
arm-none-eabi-objcopy -S -O binary ./target/thumbv6m-none-eabi/release/lab01 lab01.bin

Am I doing something wrong or is setting custom sections not supported?

The elf file works with GDB as expected, but to flash the code I need to use the bin file with the correct flash_config_field bits at 0x400.

Attached are the elf and bin files.

Thanks for the help in advance :)

lab01.elf.txt
lab01.bin.txt

I just tried to reproduce your example, and I see the region and section correctly added to the binary. But your lab01.elf doesn't have it for some reason.

Hello pftbest, thanks for the help, but I think it's the other way around, right? The ELF (which comes straight out of the compiler) has the section:

tiberiodarferreira$ arm-none-eabi-readelf -h target/thumbv6m-none-eabi/release/lab01
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x810
  Start of program headers:          52 (bytes into file)
  Start of section headers:          41592 (bytes into file)
  Flags:                             0x5000200, Version5 EABI, soft-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         12
  Section header string table index: 11
note47:lab01 tiberiodarferreira$ arm-none-eabi-readelf -S target/thumbv6m-none-eabi/release/lab01
There are 12 section headers, starting at offset 0xa278:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .flash_protect    PROGBITS        00000400 003e9c 000000 00   W  0   0  1
  [ 2] .vector_table     PROGBITS        00000410 000410 000090 00   A  0   0  4
  [ 3] .text             PROGBITS        00000810 000810 0026f4 00  AX  0   0  4
  [ 4] .rodata           PROGBITS        00002f10 002f10 000f8c 00   A  0   0 16
  [ 5] .stack            PROGBITS        1ffff0c0 003e9c 003f40 00   W  0   0  4
  [ 6] .bss              NOBITS          1ffff0c0 000000 000000 00  WA  0   0  4
  [ 7] .data             PROGBITS        1ffff0c0 007ddc 000000 00  WA  0   0  4
  [ 8] .ARM.attributes   ARM_ATTRIBUTES  00000000 007ddc 00002c 00      0   0  1
  [ 9] .symtab           SYMTAB          00000000 007e08 001140 10     10 209  4
  [10] .strtab           STRTAB          00000000 008f48 0012c5 00      0   0  1
  [11] .shstrtab         STRTAB          00000000 00a20d 000068 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  y (purecode), p (processor specific)

But for some reason the flash_configuration section ends up on the top of the binary, in the first 128 bits:
screen shot 2018-04-02 at 20 01 36

Instead of in the 0x400 region:

screen shot 2018-04-02 at 20 02 47

Here is the link to the repo with the code if you want to take a look.

https://github.com/tiberiusferreira/RUST-FRDM-KL25Z

Ok, I understand. In the lab01.elf.txt file that you've linked at the end of your first message there is no .flash_protect section, that is why I thought you don't have it. Now I see that everything is working as it should. If you look at documentation for objcopy command you can see this text:

The memory dump will start at the load address of the lowest section copied into the output file.

Your first section is located at address 0x400 so your .bin file also starts at 0x400. That's why you see your values as first bytes in the file. This is intended behavior.

But why do you need a bin file? If you want to use it for flashing your chip, please consider using elf or hex formats instead, because they do preserve such address information.

Thanks for the help so far. The lowest section would be the interrupts which go from 0x0 to 0x400, would it now?

VECTORS (rx) : ORIGIN = 0x00000000, LENGTH = 0x00000400
#[link_section = ".vector_table.interrupts"]
#[used]
static INTERRUPTS: [extern "C" fn(); 20] = [default_handler; 20];

extern "C" fn default_handler() {
    asm::bkpt();
}

I can't flash an ELF file. I'm using the "drag and drop" method, which allows me to just drag and drop the file to the board mounted as an USB mass storage device. However, it only takes bin files. Also all the examples I could find use bin files, such as https://os.mbed.com/platforms/KL25Z/#downloading-a-program .

I'm using this method because it is the easiest (or so I thought haha) and prevents me from flashing a bin file setting the flash_security bits (the bits at 0x400). Setting security bits could make the flash impossible to erase (and so bricking the board).

I took a lot of inspiration from https://github.com/0xc0170/frdm-kl25z-rust .

I didn't manage to compile that project, but the Makefile there uses arm-none-eabi-objcopy the same way I'm using.

Have you tried to use _stext? I know that some people have it for the purpose of not flashing the Flash memory that's located right after the vector table (some uCs store configuration stuff in that section).

Hello japaric.

I looked into it, but I do need to flash that memory with the right bits, I can't skip them. If I don't it's going to be filled with 0s and that is going to be interpreted as setting the security bits to 0, which could brick the board.

The lowest section would be the interrupts which go from 0x0 to 0x400, would it now?

Well, here is your problem. If you look closely at this table:

  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 2] .vector_table     PROGBITS        00000410 000410 000090 00   A  0   0  4

You can see that your vectors are placed at address 410 and not at 0. This happens because default liker script is using region FLASH for both vectors and code, and you've placed the FLASH region at address 410.

But this is easy to fix, just place the FLASH region at address 0, and use _stext symbol to move the code, as @japaric suggested. Your memory.x file should look like this:

MEMORY
{
    FLASH : ORIGIN = 0x00000000, LENGTH = 128K
    RAM   : ORIGIN = 0x1FFFF0C0, LENGTH = 16K - 0xC0
}

SECTIONS
{
    .flash_protect 0x400 :
    {
        LONG(0xFFFFFFFF);
        LONG(0xFFFFFFFF);
        LONG(0xFFFFFFFF);
        LONG(0xFFFFFFFE);
    } > FLASH
}

_stext = 0x410;

It worked!! Awesome!!

Thank you very much for the help!

Sorry for reviving an old issue but was trying out above suggestion and got:

error: linking with `rust-lld` failed: exit status: 1
  |
 ...
  = note: rust-lld: error: unable to place section .vector_table at file offset [0xFFFFFFFFFFFFFCF4, 0xFFFFFFFFFFFFFDB3]; check your linker script for overflows
          rust-lld: error: unable to place section .text at file offset [0xFFFFFFFFFFFFFDB4, 0x5B]; check your linker script for overflows
          rust-lld: error: section .rodata file range overlaps with .flash_protect
          >>> .rodata range is [0x5C, 0x1A3]
          >>> .flash_protect range is [0xF4, 0x103]

          rust-lld: error: section .rodata virtual address range overlaps with .flash_protect
          >>> .rodata range is [0x368, 0x4AF]
          >>> .flash_protect range is [0x400, 0x40F]

          rust-lld: error: section .rodata load address range overlaps with .flash_protect
          >>> .rodata range is [0x368, 0x4AF]
          >>> .flash_protect range is [0x400, 0x40F]


error: could not compile `pinscape-rust` (bin "pinscape-rust") due to previous error

Any hints on solving this?

@francisdb please share your full memory.x file, it's hard to tell from an error message

@pftbest It's exactly the one you posted above.

MEMORY
{
    FLASH : ORIGIN = 0x00000000, LENGTH = 128K
    RAM   : ORIGIN = 0x1FFFF0C0, LENGTH = 16K - 0xC0
}

SECTIONS
{
    .flash_protect 0x400 :
    {
        LONG(0xFFFFFFFF);
        LONG(0xFFFFFFFF);
        LONG(0xFFFFFFFF);
        LONG(0xFFFFFFFE);
    } > FLASH
}

_stext = 0x410;

@francisdb I just took this repo, cloned it, put your code in the memory.x and compiled and there is no issue. Can you please clarify any additional configuration I should do to reproduce this ?

Thanks @pftbest for looking into this

This issue happens only when switching .cargo/config.toml to

target = "thumbv6m-none-eabi"        # Cortex-M0 and Cortex-M0+

As I understood the FRDM-KL25Z runs an Arm® Cortex®-M0+ Core

@francisdb Ok, so what I found out is that lld really doesn't like gaps between the sections. On v7m the .vector table ends at 0x400 so there is no gap, but on v6m it ends at 0xC0 instead, there is a gap from 0xC0 to 0x400. To work around this you can start your section at 0xC0 and then manually move the dot within that section to 0x400. This should do the trick:

SECTIONS
{
    .flash_protect 0xC0 :
    {
        . = 0x400;
        LONG(0xFFFFFFFF);
        LONG(0xFFFFFFFF);
        LONG(0xFFFFFFFF);
        LONG(0xFFFFFFFE);
    } > FLASH
}

Thanks, confirming that fixes it!