assemblystm32stm32f4discovery

STM32F407 - can't write to RAM (assembly)


I'm using STM32F407 Discovery Kit and when I try to write something to RAM it doesn't work.

.thumb
.syntax unified
.cpu cortex-m4

.section .bss
NIZ: .space 4

// Start of text section
.section .text
///////////////////////////////////////////////////////////////////////////////
// Vectors
///////////////////////////////////////////////////////////////////////////////
// Vector table start
// Add all other processor specific exceptions/interrupts in order here
.long    __StackTop                // Top of the stack. from linker script
.long    _start +1                  // reset location, +1 for thumb mode

_start:
    adr r0, NIZ // address of the variable in RAM
    ldr r1, [r0] // load the value from RAM to r1
    ldr r1, =0xFE // store random value to r1
    str r1, [r0] // store value from r1 to RAM
    ldr r1, [r0] // here r1 should contain 0xFE but does not
end: b end

This is a sample program to demonstrate the problem.

The address that gets loaded into r0 is 0x08000008 but this is wrong as RAM region is in 0x20000000 as defined in linker script:

/* linker script for STM32F407VG chip */

MEMORY {
    rom (rx)  : ORIGIN = 0x08000000, LENGTH = 1024K
    ram (rwx) : ORIGIN = 0x20000000, LENGTH =  128K
}

SECTIONS {
    .text ORIGIN(rom) :
    {
        KEEP(*(.vectors))  /* Vector table */
        *(.text*)          /* Program code */
        *(.rodata*)        /* Read only data */
        . = ALIGN(4);
        __etext = .;
    }

    _sidata = .;

    .data ORIGIN(ram) :  AT ( ADDR (.text) + SIZEOF (.text) )
    {
        __data_start__ = .;
        *(.data*)      /* Read-write initialized data */
        . = ALIGN(4);
        __data_end__ = .;
    }


    .bss ADDR (.data) + SIZEOF (.data):
    {
        __bss_start__ = .;
        . = ALIGN(4);
        *(.bss*)       /* Read-write zero initialized data */
        *(COMMON)
        . = ALIGN(4);
        __bss_end__ = .;
    }
}

__StackTop = ORIGIN(ram) + LENGTH(ram);
__text_size = SIZEOF (.text);
__data_size = SIZEOF (.data);
__bss_size  = SIZEOF (.bss);

My project is a clone of this: https://github.com/fcayci/stm32f4-assembly

So my guess is the address is somehow in the wrong range and I'm not sure what causes this or how to fix it.

EDIT:

readelf -s Debug/stm32f4-asm.elf                                                         ✔ 

Symbol table '.symtab' contains 27 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 08000000     0 SECTION LOCAL  DEFAULT    1 .text
     2: 20000000     0 SECTION LOCAL  DEFAULT    2 .data
     3: 20000000     0 SECTION LOCAL  DEFAULT    3 .bss
     4: 00000000     0 SECTION LOCAL  DEFAULT    4 .ARM.attributes
     5: 00000000     0 SECTION LOCAL  DEFAULT    5 .debug_line
     6: 00000000     0 SECTION LOCAL  DEFAULT    6 .debug_info
     7: 00000000     0 SECTION LOCAL  DEFAULT    7 .debug_abbrev
     8: 00000000     0 SECTION LOCAL  DEFAULT    8 .debug_aranges
     9: 00000000     0 SECTION LOCAL  DEFAULT    9 .debug_str
    10: 00000000     0 FILE    LOCAL  DEFAULT  ABS ./test.o
    11: 20000000     0 NOTYPE  LOCAL  DEFAULT    3 NIZ
    12: 20000000     0 NOTYPE  LOCAL  DEFAULT    3 $d
    13: 08000008     0 NOTYPE  LOCAL  DEFAULT    1 _start
    14: 08000000     0 NOTYPE  LOCAL  DEFAULT    1 $d
    15: 08000008     0 NOTYPE  LOCAL  DEFAULT    1 $t
    16: 08000016     0 NOTYPE  LOCAL  DEFAULT    1 end
    17: 00000000     0 NOTYPE  GLOBAL DEFAULT  ABS __data_size
    18: 20000000     0 NOTYPE  GLOBAL DEFAULT    2 __data_start__
    19: 08000018     0 NOTYPE  GLOBAL DEFAULT    1 _sidata
    20: 08000018     0 NOTYPE  GLOBAL DEFAULT    1 __etext
    21: 00000004     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_size
    22: 20000000     0 NOTYPE  GLOBAL DEFAULT    3 __bss_start__
    23: 20000000     0 NOTYPE  GLOBAL DEFAULT    2 __data_end__
    24: 20000004     0 NOTYPE  GLOBAL DEFAULT    3 __bss_end__
    25: 20020000     0 NOTYPE  GLOBAL DEFAULT    3 __StackTop
    26: 00000018     0 NOTYPE  GLOBAL DEFAULT  ABS __text_size
readelf -s Debug/test.o                                                                  ✔ 

Symbol table '.symtab' contains 17 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 SECTION LOCAL  DEFAULT    1 .text
     2: 00000000     0 SECTION LOCAL  DEFAULT    3 .data
     3: 00000000     0 SECTION LOCAL  DEFAULT    4 .bss
     4: 00000000     0 NOTYPE  LOCAL  DEFAULT    4 NIZ
     5: 00000000     0 NOTYPE  LOCAL  DEFAULT    4 $d
     6: 00000008     0 NOTYPE  LOCAL  DEFAULT    1 _start
     7: 00000000     0 NOTYPE  LOCAL  DEFAULT    1 $d
     8: 00000008     0 NOTYPE  LOCAL  DEFAULT    1 $t
     9: 00000016     0 NOTYPE  LOCAL  DEFAULT    1 end
    10: 00000000     0 SECTION LOCAL  DEFAULT    7 .debug_info
    11: 00000000     0 SECTION LOCAL  DEFAULT    9 .debug_abbrev
    12: 00000000     0 SECTION LOCAL  DEFAULT    5 .debug_line
    13: 00000000     0 SECTION LOCAL  DEFAULT   12 .debug_str
    14: 00000000     0 SECTION LOCAL  DEFAULT   10 .debug_aranges
    15: 00000000     0 SECTION LOCAL  DEFAULT   13 .ARM.attributes
    16: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND __StackTop
readelf -l Debug/stm32f4-asm.elf                                                         ✔ 

Elf file type is EXEC (Executable file)
Entry point 0x8000000
There are 2 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x010000 0x08000000 0x08000000 0x00018 0x00018 R E 0x10000
  LOAD           0x020000 0x20000000 0x08000018 0x00000 0x00004 RW  0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .text 
   01     .data .bss

Solution

  • So my guess is the address is somehow in the wrong range and I'm not sure what causes this or how to fix it.

    Sorry for asking you about the outputs of readelf; I just checked on my computer and found out that it is not a linking problem but an assembler problem.

    The following line is the issue:

    ADR R0, NIZ
    

    According to the official ARM documentation (not the GNU documentation), the ADR instruction is only allowed if the symbol (here: NIZ) is in the same section (and the same file) as the ADR instruction.

    GNU assembler should print an error message because the symbol NIZ and the ADR instruction are in different sections; however, it silently ignores the error and generates wrong code!

    The following line worked for me:

    LDR R0, =NIZ