Dmitry,Quite right, you are. I As you suggest, I get similar results on i386 when using pointers that involve the sign bit. I find that a bit troubling for i386 as well. It would seem that subtracting pointers can in general be unsafe. I suppose it would be prudent to cast them to unsigned types and go from there.
Thanks for your insight.
Walt Dmitry wrote:
Well, this problem is more 'general C' than msp430 I think... Agree, this is not documented (yet), however:Well, pointers usually have to same size as 'int'. In case of msp430 this is 2 bytes. Usually, compilers operate with pointers as with 'unsigned int' variable. (at least in case of mspgcc unless you pass -mint8).However, when you 'diff' two pointers gcc considers this to be 'signed int'(still 2 bytes). Then divides this 'diff' by type size in order 'diff' to be equial the number of 'type' elements between two pointers.So, the thing you see in your example:(0x7000 - 0x1000) >> 2 == 0x1800; 2 bytes. Extend to 4 byte var gives 0x00001800(0xf000-0x1000) >> 2 == 0xe000>>2 == 0xf800; 2 bytes. Extend to 4 bytes gives 0xfffff800In case you're play with i368, the last numbers are: (0x0000f0000 - 0x000010000) >>2 == 0x0000e000 >> 2 == 0x00003800 To prove this, try 0x10000000 and 0xf0000000 on i368 and check. Hope this helps. ~d On Tuesday 31 December 2002 05:17, Walt Spicker wrote:David, Your point is well taken. I guess this could be considered inconsequential given the memory layout of the MSP430s. I stumbled across it in an application that transmits large chunks of data stored in an external memory. I don't have the external memory available at present, so I was just dumping the contents of flash in order to have something to send. I then noticed that my pointers did not have the expected values when I started walking through memory. So I contrived a simple example to demonstrate the problem, and here we are. I don't really think that I need to see this get fixed, but it does seem to expose a weakness in the generated code that may have more important side affects elsewhere. Thanks again, Walt David Dyck wrote:Your initial test program should get people thinking, but perhaps it is now time to go back to the mailing list with the assembly language pointer divide by 4. maybe post a simplified program, although the list may argue that the result is undefined since at this time you can have an array of longs that are this big in the msp430, but a "long" checksum routine with 60k of flash may be a contrived example. perhaps even a const long array in the code section that just happens to cross the 32k byte boundary would also experience this size failure.On Mon, 30 Dec 2002 at 17:14 -0500, walt spicker<[email protected]...:From: walt spicker <[email protected]> To: David Dyck <[email protected]> Date: Mon, 30 Dec 2002 17:14:09 -0500 Subject: Re: [Mspgcc-users] Pointer Arithmetic Error David, As you suggest, I took a peek at the assembly, and it appears to me that there is a problem with the instruction used to do the divide by 4. Indeed the compiler is using "rra" to divide the pointer value "0xf000" by 4. with the resulting value being "0xf800", probably not what was intended. Is there a mechanism to report a "bug", or do we just hope this bubbles up and and gets the attention of somone with the ability to fix it? Thanks for your help, Walt David Dyck wrote: Walt, perhaps it is time to look at the assembly code generated, perhaps the msp code is treating the number as signed. Another thing to try would be to check out the same code with pointers to characters instead of longs, so the compiler wouldn't have to do divisions by 4 (maybe right shift). Also, what optimizations are the compiler generating - perhaps it can pre-compute some of the math - so there are a couple opportunities for errors here... On Mon, 30 Dec 2002 at 15:27 -0500, walt spicker < [email protected]...: <mailto:[email protected]...:> Thanks for your reply. I sort of see what you are getting at, but that does not appear to be the problem. Here is a modified test, first on the 430: unsigned long *p1=(void*)0x1000LU, *p2=(void*)0x7000LU, *p3=(void*)0xf000LU; unsigned long p2p1 = p2-p1; unsigned long p3p1 = p3-p1; static char buf[80]; snprintf (buf, sizeof(buf), "%8.8lx %8.8lx %p %p %p %i", p2p1, p3p1, p1, p2, p3, sizeof(p3)); PrintLine (buf); Output from 430 test: 00001800 fffff800 0x1000 0x7000 0xf000 2 Here is the modified test, on the 386/Linux main(){ unsigned long *p1=(void*)0x1000LU, *p2=(void*)0x7000LU, *p3=(void*)0xf000LU; unsigned long p2p1 = p2-p1; unsigned long p3p1 = p3-p1; printf ("%8.8lx %8.8lx %p %p %p %i \n", p2p1, p3p1, p1, p2, p3, sizeof(p3)); } Output 386/Linux 00001800 00003800 0x1000 0x7000 0xf000 4 OK, so the size of the pointer on the 430 is two bytes vs. 4 bytes on the I386. I do not see what role that plays here. My expectation is that the difference between two pointers of the same type will yield the number of those items that would fit in memory between the two addresses. This seems to be true on the 430 only when the MSB of the pointers is zero. Please let me know if you still think that I'm missing something here.
