Wrong assembly code generated from C code (ARM Cortex-m3) ?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

I got a problem with an assembly code generated by GCC from a C code.


A little bit of context:

I try to write a minimal firmware for a micro-controller, the LPC1769.
It use ARM Cortex-M3 CPU. My firmware is simple:
* Run a function named "reset()" at CPU reset
* In this function, I declare 3 locals variables: 3 pointers to 3
  differents registers, initialized with their address
* Then, I write a value in each register


The problem: 

The CPU reset after the first value I write in a register

This is the code of the function "reset()":
``` c
void reset() {
  // Define some registers
  // Register to define mode of the pins P0.16 to P0.26
  unsigned int *PINMODE1 = (unsigned int *)0x4002C044;
  // Register to define GPIO direction of pins P0.0 to P0.31
  unsigned int *FIO0DIR = (unsigned int *)0x2009C000;
  // Register to define GPIO value of pins P0.0 to P0.31
  unsigned int *FIO0SET = (unsigned int *)0x2009C018;

  // Config the GPIO to drive a LED
  // Enable P0.22 pin to put the line to ground
  *PINMODE1 = 0x00003000;
  // Set P0.22 as GPIO output
  *FIO0DIR = 0x400000;

  // To the eternity
  while (1) {
    // Wait
    for (int i = 0; i < 500000; ++i);

    // Toggle the LED via P0.22
    *FIO0SET ^= (0b1<<22);
  }
  
}
```

The problem is at the line `*PINMODE1 = 0x00003000;`. This is the
assembly code generated by GCC and view from GDB:

``` assembly
=> 0x0000001a <+18>:	ldr	r3, [r7, #8]
   0x0000001c <+20>:	strb	r6, [r0, #28]
   0x0000001e <+22>:			; <UNDEFINED> instruction: 0xf590601a
   0x00000022 <+26>:	ldr	r3, [r7, #4]
```

The first assembly code, ldr, load the address `0x4002C044` into the
register `r3`. But the second asm code, `strb`, is it store the value
from the register `r6` to the address made frome the value of register
`r0` plus a shift of 28 ? Why not simply copy the value `0x00003000`
to the adress stored in `r3` register ? Why this undefined instruction
`0xf590601a` ? This third asm code, the "undefied" `0xf590601a` is the
instruction that make the CPU reset. 

I'm not an expert in assemply and I don't know if it's me that don't
understand it of if the assembly code generated by GCC is wrong. Any
help is welcome. ;)

Thank you. :)

This is the version of arm-none-eabi-gcc I use: 
11.1.0 (Fedora 11.1.0-2.fc35)

Version of GDB: 
11.1 (Fedora 11.1-2.fc35)

Version of OpenOCD:
0.11.0 (from Fedora repo)

This is the full C code:
``` c
/* reset

Function run right after the reset of the CPU
 */
void reset() {
  // Define some registers
  // Register to define mode of the pins P0.16 to P0.26
  unsigned int *PINMODE1 = (unsigned int *)0x4002C044;
  // Register to define GPIO direction of pins P0.0 to P0.31
  unsigned int *FIO0DIR = (unsigned int *)0x2009C000;
  // Register to define GPIO value of pins P0.0 to P0.31
  unsigned int *FIO0SET = (unsigned int *)0x2009C018;
  
  // Config the GPIO to drive a LED
  // Enable P0.22 pin to put the line to ground
  /* *PINMODE1 |= (0x1<<12); */
  /* *PINMODE1 |= (0x1<<13); */
  *PINMODE1 = 0x00003000;
  // Set P0.22 as GPIO output
  /* *FIO0DIR |= (0x1<<22); */
  *FIO0DIR = 0x400000;

  // To the eternity
  while (1) {
    // Wait
    for (int i = 0; i < 500000; ++i);

    // Toggle the LED via P0.22
    *FIO0SET ^= (0b1<<22);
  }
  
}

int STACK[256];

const void *vectors[] __attribute__ ((section (".vectors"))) = {
  STACK + sizeof(STACK) / sizeof(*STACK),
  reset
};
```


This is my link script:
```
MEMORY {
    flash (RX) : ORIGIN = 0x00000000, LENGTH = 512K
    sram (RW!X) : ORIGIN = 0x10000000, LENGTH = 32K
}
SECTIONS {
    .vectors    : { *(.vectors) } >flash
    .text       : { *(.text) } >flash
    .rodata     : { *(.rodata) } >flash
    .bss        : { *(.bss) } >sram
}
```

This is my Makefile:
```
CFLAGS = -g -O0 -Wall
CFLAGS += -mthumb -mcpu=cortex-m3 

CC = arm-none-eabi-gcc
LD = arm-none-eabi-ld
OBJCPY = arm-none-eabi-objcopy


all: blink.bin


blink.bin: blink.elf
	@echo "Make the binary"
	$(OBJCPY) -O binary blink.elf blink.bin

blink.elf: blink.o
	@echo "Linkage"
	$(LD) -T blink.ld -o blink.elf blink.o

blink.o: blink.c
	@echo "Compile the code"
	$(CC)  -c $(CFLAGS) -o blink.o blink.c

clean:
	@echo "Clean the working dir"
	rm blink.o blink.elf blink.bin

debug: blink.elf
	gdb -x gdbconfig blink.elf

debug-mi: blink.elf
	gdb -i=mi -x gdbconfig blink.elf
```




[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux