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

*((int *)&Buf[2]) = 0x12345678;

RVMDK v3.00a, Hello World sample for RealView compiler

#pragma pack(1)

unsigned char Buf[40];

int main (void)
{
*((short int *)&Buf[0]) = 0x77ff;
*((int *)&Buf[2]) = 0x12345678;
/* initialize the serial interface */
PINSEL0 = 0x00050000;
U1LCR = 0x83;
U1DLL = 97;
U1LCR = 0x03;

printf ("Hello World\n");
printf("%x %x %x %x \n", Buf[0],Buf[1],Buf[2],Buf[3]);
}

Hello World

78 56 34 12
------------
The same thing is for CARM compiler 2.4, 2.5

What I am wrong ?

  • From the 'ARM Architecture Reference Manual':

    ARM processors support the following data types:
    - Byte 8 bits
    - Halfword 16 bits (halfwords must be aligned to two-byte boundaries)
    - Word 32 bits (words must be aligned to four-byte boundaries)

    You are trying to write a word to an address location which is not aligned to a 4-byte boundary. I'm not sure what pragma pack(1) is supposed to do. I suspect it has something to do with structure packing and padding bytes. In other words, pragma pack(1) will not solve this problem.

    - mike

  • Well, I am trying to write a word to an address location which is not aligned to a 4-byte boundary. But Is not it compiler realisation's problem/task ?
    Or as minimum there should be some mention in docs/faqs on how to handle such sitiations

  • Well, I am trying to write a word to an address location which is not aligned to a 4-byte boundary. But Is not it compiler realisation's problem/task ?
    Or as minimum there should be some mention in docs/faqs on how to handle such sitiations

  • Well, there is one.

    _packed extention


    Kind regards to those goblins who write doc's and readme!

  • But Is not it compiler realisation's problem/task ?

    No. It's your task not to try to make your code do something that the CPU can't do.

  • Well, I am trying to write a word to an address location which is not aligned to a 4-byte boundary. But Is not it compiler realisation's problem/task ?

    It appears you try to force the CPU to do what is not designed for, but it speaks gently back to you, for the unaligned word access will perform a deterministic byte rotation of word reads (ldr); and it will mask the unaligned address with 0xFFFFFFFE for unaligned writes (str).
    On ARM cores with a system control processor (such as CP15 on ARM720T), one can select whether to raise a data abort exception on unaligned access to memory, or not.
    On ARM7TDMI-S, this is not an option, and therefore the unaligned accesses will *not* raise data abort exception, even though ARM ARM states so. Be carefull going from general to specific claims, it all depends on the context and implementation.
    It is not a compiler's problem.

    Be well.

  • It's the compiler's job (actually the linker's) to make sure that multi-byte objects are properly aligned. But once you start taking addresses of individual bytes and manipulating those addresses, you take the responsibility of maintaining proper alignment on yourself.

    Few RISC processors operate correctly with misaligned data. Most of them take an exception. The ARM core does not, but external memory hardware might.

  • Kind regards to those goblins who write doc's and readme!

    'Goblins'. very kind, indeed. I can think of different words.

    Erik

  • You must use -

      *((__packed int *)&Buf[2]) = 0x12345678;
    
    Without __packed you are telling the compiler '(int *)&Buf[2]' is a properly 32-bit aligned address, which is likely to be not the case.

  • One common problem with this is typecasting. I had a "fun time" once (on an XA) finding that when typecastion a char to an int you did not "see" the alignment problem.

    so, as of the, it is a rule that nothing can be typecase "upwards"

    Erik

  • One common problem with this is typecasting. I had a "fun time" once (on an XA) finding that when typecastion a char to an int you did not "see" the alignment problem.

    typecasting is only way of saying to compiler how many bytes we copy to some place. I have never see any aligment problems due to typecasting. A lot of unix stuff use things like in subj(summary) as well as in intel sources

  • I have never see any aligment problems due to typecasting

    Then you've been lucky. Or, depending on your processor, you just haven't noticed. Some processors will run correctly, but slower, with misaligned accesses.

    Try this code on your processor of choice that requires alignment:

    U8 bytes[4];
    U32 dest;

    ...
    dest = *(U32*)&bytes[0];
    dest = *(U32*)&bytes[1];
    dest = *(U32*)&bytes[2];
    dest = *(U32*)&bytes[3];

    and you'll see a misaligned access at some point. Without the typecast, the compiler could detect the misalignment. With the typecast, I've assured the compiler that everything is okay and that I know what I'm doing -- which, in this case, is the wrong thing in three out of four cases.

  • I think you missed Evegeny's point a bit because you understand a different thing under the term "typecast" than he does.

    U8 bytes[4];
    U32 dest;
    
    ...
    dest = *(U32*)&bytes[0];
    dest = *(U32*)&bytes[1];
    dest = *(U32*)&bytes[2];
    dest = *(U32*)&bytes[3];
    
    [...] Without the typecast, the compiler could detect the misalignment. Not really. Without the casts, that snippet completely changes semantics. It becomes equivalent to four assignments of a char value to a U32 variable, like this:

    dest = bytes[0];
    dest = bytes[1];
    dest = bytes[2];
    dest = bytes[3];

    Type casts are one thing. Your example (like the one that started the thread) is about pointer casts, and those are forbidden by the C language. For good reason, too.

  • then what about this one

    U8 bytes[4];
    U32 dest;

    ...
    dest = (U32)&bytes[0];
    dest = (U32)&bytes[1];
    dest = (U32)&bytes[2];
    dest = (U32)&bytes[3];


    Erik

  • dest = (U32)&bytes[1];


    This is equivalent to

    dest = (U32)(bytes + 1);

    by requirement (C99 6.5.3.2, phrase 3). I.e. it's pointer arithmetic on pointers to bytes (always allowed), followed by a cast of a pointer value to an integer value. You get an Implementation-defined result, instead of undefined behaviour.