Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12600 Discussions

Pointer help - alignment issue

Altera_Forum
Honored Contributor II
1,714 Views

I need to use a pointer to a long that is not word aligned (I think). Here is sample code 

 

void func(void) 

char Test[12] = { 1, 2, 3,4 ,5 ,6, 7, 8, 9, 10, 11, 12}; 

long * temp; 

temp = (long *) &Test[0]; 

printf("Starting at Test[0] *%d = %X\n", temp, *temp); 

temp = (long *) &Test[1]; 

printf("Starting at Test[1] *%d = %X\n", temp, *temp); 

temp = (long *) &Test[2]; 

printf("Starting at Test[2] *%d = %X\n", temp, *temp); 

temp = (long *) &Test[3]; 

printf("Starting at Test[3] *%d = %X\n", temp, *temp); 

temp = (long *) &Test[4]; 

printf("Starting at Test[4] *%d = %X\n", temp, *temp); 

temp = (long *) &Test[5]; 

printf("Starting at Test[5] *%d = %X\n", temp, *temp); 

 

and the output 

 

Starting at Test[0] *50331608 = 4030201 

Starting at Test[1] *50331609 = 4030201 

Starting at Test[2] *50331610 = 4030201 

Starting at Test[3] *50331611 = 4030201 

Starting at Test[4] *50331612 = 8070605 

Starting at Test[5] *50331613 = 8070605 

 

How come the second value is no 5040302? I am assuming that the compiler is word aligning the pointer (basically anding with 0xFFFFFFFC). I think I need to use  

long * __unaligned temp; 

but I get an error 

expected initializer before "temp" 

Do I need some include that I missed in the documentation? 

 

thanks in Advance
0 Kudos
9 Replies
Altera_Forum
Honored Contributor II
626 Views

The hardware will be ignoring the low bits, since it can't do misaligned transfers. 

(It is possible to enable an interupt on such alignment errors.) 

So whatever happens, the generated instructions will have to read both 32bit words, then shift and mask the required parts together. 

Usually it is easiest to do (for little endian): 

p | p << 8 | p << 16 | p << 24With gcc you can mark data (or types) as having a smaller alignment using the __attribute__((aligned(n))) directive (this works for sparc, I don't know if it would require special code in the nios files). 

However you do need to apply it to the correct item, ie the memory item, not the pointer variable! I think this is: 

typedef long misaligned_long __attribute__((aligned(1))); misaligned_long *p;However all this will do is cause the compiler to generate the shifts etc. 

(attribute packed can be used to get a similar effect on all the fields of a structure.)
0 Kudos
Altera_Forum
Honored Contributor II
626 Views

Thanks for the response. I could not get the __attribute__ to work. No error but the same results. I have never used it so maybe I did something wrong. I realized that both words would have to be read and adjusted. My fall back is to cast to a char* and run a loop of 4. 

 

I had a structure that was packed. One of the items gets cast as a void * and then back to a int *. When that happens apparently the alignment is lost.
0 Kudos
Altera_Forum
Honored Contributor II
626 Views

typedef int64_t netbsd32_int64 __attribute__((__aligned__(4))); 

 

Certainly works to give a 64bit int with 4 byte alignment. 

The same is used elsewhere to generate 2-byte aligned 32bit quantities. 

 

Note that if you copy the address to any pointer variable, that must be a pointer to the constrained type. 

 

I wouldn't use a loop, just do the shifts and ors - you don't want the loop overheads. 

 

There is another gotcha as well, recent gcc (probably 4.something) will track the alignment constraints through certain casts. Since the C language doesn't allow you to generate misaligned pointers to aligned types (and the only valid used of void * require you to cast the pointer back to its original type), it will assume that pointers are aligned. 

This means the following won't work. 

void fn(struct foo *fp) { struct foo f; memcpy(&f, fp, sizeof f);when the input pointer might be msialigned. The compiler will inline memcpy() and optimise for aligned pointers.
0 Kudos
Altera_Forum
Honored Contributor II
626 Views

Here are other examples: http://gcc.gnu.org/onlinedocs/gcc-3.2.3/gcc/type-attributes.html 

 

I would expect your results to be the same since if you align that array to a 4 byte boundary then when you start casting the char pointer to a long for elements [1], [2], [3], [5], [6], etc... of the char array and then performing 32-bit access based on those locations you are performing unaligned accesses again. 

 

In the end what are you trying to do? (i.e. what are you trying to do in your real code that caused you to write this test code?)
0 Kudos
Altera_Forum
Honored Contributor II
626 Views

The device I am working with started with a SCSI interface and was locked into certain data formats. They are a mixture of bytes, shorts, and integers. I can't change the structure with out changing the host interface (which would then not work with old devices).

0 Kudos
Altera_Forum
Honored Contributor II
626 Views

Do you also have a byte endianness issue? 

We wrote a single custom instruction that uses the 'b' field (usually a custom instruction register number) to select between various bit and byte swaps (more useful than the Altera instruction). 

 

If you are processing SCSI commands then, IIRC, you have a 32bit value that is 2-byte aligned. Applting __attribute__((aligned(2))) to that field (of the structure that defines the message layout) should make gcc generate two 16bit load/stores with the required shifts. 

(If you apply 'packed' to the entire structue all fields will be read as bytes since the alignment of the structure itself is unknown.) 

 

I've just done a quick test (with gcc 3.4.6) the __attribute__((aligned(1))) works - for arrays and structure members, but not simple variables. 

Feed: 

int v __attribute__((aligned(2))); int get_v(void) { return v; };into gcc -O2 -S and cat the .s file.
0 Kudos
Altera_Forum
Honored Contributor II
626 Views

Yes, I have/had an endian issue. The original code was written for an X86 so most of that is already handled.  

 

The casting is a limited problems since most functions didn't go through the recast so do not have an issue. I have one function that was causing problems. It took 2 void pointers and cast them as long pointers then copied the contents of one location to another. For right now I have cast them as character pointers and copy 4 characters. I will come back and optimize it later :) 

 

 

--- Quote Start ---  

I've just done a quick test (with gcc 3.4.6) the __attribute__((aligned(1))) works - for arrays and structure members, but not simple variables. 

--- Quote End ---  

 

This maybe why my test did not work. I tried something like 

 

int * __attribute__((aligned(1))) pvar; 

 

Which is a simple variable and as mentioned above saw no change.
0 Kudos
Altera_Forum
Honored Contributor II
626 Views

Actually that one tries to apply the attribute to pvar, not *pvar. 

Define a type that has the attribute attached, otherwise it is difficult to get it applied to the right place (even when it does work). 

 

A structure containing a single alignment-contrained integer does work. 

So maybe you need: 

typedef struct { int v __attribute__((aligned(2))); } int_aligned_16_t; 

and use that inside the other structures - so you only look at the 'v' member when you want the value itself.
0 Kudos
Altera_Forum
Honored Contributor II
626 Views

Thanks, I will give that a try when I am back on schedule.

0 Kudos
Reply