This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

LDRD instruction confused me, please help

I used keil mdk v5.1 for arm to develop my project.
I encounterd a serious problem about LDRD instruction.
Look at c codes below:

#include <stdint.h>

char b[2];
char c[4];
char d[2];

typedef struct {
        uint32_t                m_front;                        /* ¶ÓÍ·         */
        uint32_t                m_rear;                         /* ¶Óβ        */
        uint16_t                m_maxData;                      /* ¶ÓÁÐÖÐÔÊÐí´æ´¢µÄÊý¾Ý¸öÊý */

        uint8_t         (* ReadEmpty)();                /* ¶Á¿Õ´¦Àíº¯Êý             */
        uint8_t         (* WriteFull)();                /* дÂú´¦Àíº¯Êý             */
} DataQueue;

void SystemInit()
{
}

void main()
{
    DataQueue* p = (DataQueue*)c;

    char* q = c;
    char* xx = b;
    char* yy = d;

    if (p->m_front == p->m_rear)
    {
        int i = 0;
    }
}

disassembly of part of c codes is below

    28:     if (p->m_front == p->m_rear)
    29:     {
0x08000194 E9D04500  LDRD     r4,r5,[r0,#0]
0x08000198 42AC      CMP      r4,r5
0x0800019A D101      BNE      0x080001A0
    30:         int i = 0;
0x0800019C 2400      MOVS     r4,#0x00
    31:     }

I started a debug session.
When I stepped over sentance "if (p->m_front == p->m_rear)",
I found that program crashed(Hard fault error).

i thought that LDRD need value of r0 to a multiple of 4,
but r0 value was 0x20000002 at this time.

so i have to add __align(4) keyword to make sure that address of "c" is multiple of 4 and everything is fine.
you can see the codes below

#include <stdint.h>

char b[2];
__align(4) char c[4];
char d[2];

typedef struct {
        uint32_t                m_front;                        /* ¶ÓÍ·         */
        uint32_t                m_rear;                         /* ¶Óβ        */
        uint16_t                m_maxData;                      /* ¶ÓÁÐÖÐÔÊÐí´æ´¢µÄÊý¾Ý¸öÊý */

        uint8_t         (* ReadEmpty)();                /* ¶Á¿Õ´¦Àíº¯Êý             */
        uint8_t         (* WriteFull)();                /* дÂú´¦Àíº¯Êý             */
} DataQueue;

void SystemInit()
{
}

void main()
{
        DataQueue* p = (DataQueue*)c;

    char* q = c;
    char* xx = b;
    char* yy = d;

    if (p->m_front == p->m_rear)
    {
        int i = 0;
    }
}

i was confused if this was an bug of compiler?
Please help me

Parents
  • Dear Pier

    Thanks for your reply.
    I saw that char array is not big enough.
    But even it was enlarged, such issue still existed.

    My MCU was STM32F103C8 which core was cortex-m3.
    Assume that char array's first element's address is 0x20000000.
    I tested severval unaligned read below.

    #include <stdint.h>
    
    char array[200];                              //first element's address is 0x20000000
    
    typedef struct {
            uint32_t                m_front;                        /* ¶ÓÍ·         */
            uint32_t                m_rear;                         /* ¶Óβ        */
            uint16_t                m_maxData;                      /* ¶ÓÁÐÖÐÔÊÐí´æ´¢µÄÊý¾Ý¸öÊý */
    
            uint8_t         (* ReadEmpty)();                /* ¶Á¿Õ´¦Àíº¯Êý             */
            uint8_t         (* WriteFull)();                /* дÂú´¦Àíº¯Êý             */
    } DataQueue;
    
    void SystemInit()
    {
    }
    
    void main()
    {
    
        uint32_t arrayAddr = (uint32_t)array;
    
        uint32_t* pINT = (uint32_t*)(arrayAddr + 1);  //address is 0x20000001
        uint32_t valINT = *pINT;                      //It's OK. It used LRD instruction.
    
        float* pFLOAT = (float*)(arrayAddr + 1);      //address is 0x20000001
        float valFLOAT = *pFLOAT;                     //It's OK
    
        DataQueue* pQueue = (DataQueue*)(arrayAddr + 1);//address is 0x20000001
        uint32_t front = pQueue->m_front;                  //It's OK. It used LRD instruction.
        uint32_t rear = pQueue->m_rear;                    //It's OK. It used LRD instruction.
    
        if (pQueue->m_front == pQueue->m_rear)
        {
            front = rear;                             //crashed here
        }
    }
    
    

    I found that only LDRD instruction would crash program, but LRD instruction is OK.
    If i used IAR compiler to compile this program, it's OK.
    Because there is no LDRD instruction.

    There were many casting structure(packed or unpacked) such as DataQueue in my project.
    what should i do to prevent those crashes?

    Looking forward to your reply.

Reply
  • Dear Pier

    Thanks for your reply.
    I saw that char array is not big enough.
    But even it was enlarged, such issue still existed.

    My MCU was STM32F103C8 which core was cortex-m3.
    Assume that char array's first element's address is 0x20000000.
    I tested severval unaligned read below.

    #include <stdint.h>
    
    char array[200];                              //first element's address is 0x20000000
    
    typedef struct {
            uint32_t                m_front;                        /* ¶ÓÍ·         */
            uint32_t                m_rear;                         /* ¶Óβ        */
            uint16_t                m_maxData;                      /* ¶ÓÁÐÖÐÔÊÐí´æ´¢µÄÊý¾Ý¸öÊý */
    
            uint8_t         (* ReadEmpty)();                /* ¶Á¿Õ´¦Àíº¯Êý             */
            uint8_t         (* WriteFull)();                /* дÂú´¦Àíº¯Êý             */
    } DataQueue;
    
    void SystemInit()
    {
    }
    
    void main()
    {
    
        uint32_t arrayAddr = (uint32_t)array;
    
        uint32_t* pINT = (uint32_t*)(arrayAddr + 1);  //address is 0x20000001
        uint32_t valINT = *pINT;                      //It's OK. It used LRD instruction.
    
        float* pFLOAT = (float*)(arrayAddr + 1);      //address is 0x20000001
        float valFLOAT = *pFLOAT;                     //It's OK
    
        DataQueue* pQueue = (DataQueue*)(arrayAddr + 1);//address is 0x20000001
        uint32_t front = pQueue->m_front;                  //It's OK. It used LRD instruction.
        uint32_t rear = pQueue->m_rear;                    //It's OK. It used LRD instruction.
    
        if (pQueue->m_front == pQueue->m_rear)
        {
            front = rear;                             //crashed here
        }
    }
    
    

    I found that only LDRD instruction would crash program, but LRD instruction is OK.
    If i used IAR compiler to compile this program, it's OK.
    Because there is no LDRD instruction.

    There were many casting structure(packed or unpacked) such as DataQueue in my project.
    what should i do to prevent those crashes?

    Looking forward to your reply.

Children
  • There were many casting structure(packed or unpacked) such as DataQueue in my project.
    what should i do to prevent those crashes?

    Get rid of all the "packed" attributes. They cause a whole lot of grief (including the unaligned accesses you're so worried about), for hardly any benefit.

  • If i used IAR compiler to compile this program, it's OK.

    No, it's not OK in any sensible meaning of the word.

    That program, as written, is terminally sick. The fact it doesn't die quite as horribly and immediately if built by a different compiler, or with different flags, doesn't make the program itself any healthier. It just means its manifest illness will express itself in a different way. Or do you really believe getting garbage results instead of an immediate hard fault is in any sense of the word "OK"?

    Every single line of that program which you commented as "It's OK" actually causes undefined behaviour. In case you don't recognize that term: that's the worst kind of error a C program can have while still being compilable at all.

    Your fixation on the instruction being used by the compiler is misleading you. It's not the compiler, nor the compiled code that's the problem here. It's the source code that's grossly incorrect.