|
|
View previous topic :: View next topic |
Author |
Message |
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
[Solved]CCS compiler: passing address of pointer to function |
Posted: Sun Dec 08, 2019 9:47 pm |
|
|
I was bringing over some code I used previously on an ARM system (and also PC) and found odd behavior on the CCS compiler.
The functions take the *address* of a pointer to a buffer, then either get or put data in the buffer and increment the pointer accordingly.
Code: | uint8_t buffer[32];
uint8_t *ptr = &buffer[0];
value = get8 (&ptr);
value = get16 (&ptr);
value = get32 (&ptr); |
...and so on.
There are corresponding functions that put bytes into the buffer:
Code: | put8 (&ptr, 0x22);
put16 (&ptr, 0x1234);
put32 (&ptr, 0xaabbccdd); |
The ptr pointers returns adjusted forward.
On the PIC24, the put routines seem to work fine, but I get a crash on the gets. Here's example code:
Code: | void put8 (uint8_t **destPtr, uint8_t value)
{
// This doesn't work for me on the CCS compiler.
//memcpy (*destPtr, &data, sizeof(data));
(*destPtr)[0] = value;
(*destPtr) += sizeof(value);
}
uint8_t get8 (uint8_t **sourcePtr)
{
uint8_t value;
//memcpy(&value, *sourcePtr, sizeof(value));
//(*(uint8_t*)sourcePtr) += sizeof(value);
value = (*sourcePtr)[0];
(*sourcePtr)++;
return value; // TODO: add error checking!
} |
Here is a small code sample that crashes on my system:
Code: | uint8_t buffer[32];
uint8_t *ptr;
unsigned int value1, value2, value3;
memset (buffer, 0x0, sizeof(buffer));
ptr = &buffer[0];
// Put some data in.
put8 (&ptr, 0x11);
put8 (&ptr, 0x22);
put8 (&ptr, 0x33);
// Rewind and get the data out.
ptr = &buffer[0];
value1 = get8 (&ptr);
value2 = get8 (&ptr);
value3 = get8 (&ptr); |
The pointers seem to be as I expect. I did this quick test:
Code: | void pointerTest (uint8_t **ptrPtr)
{
printf (" ptrPtr = 0x%x\r\n", (unsigned int)ptrPtr);
printf ("*ptrPtr = 0x%x\r\n", (unsigned int)*ptrPtr);
}
void main (void)
{
uint8_t buffer[32];
uint8_t *ptr;
memset (buffer, 0x0, sizeof(buffer));
ptr = &buffer[0];
printf (" ptr = 0x%x\r\n", (unsigned int)ptr);
printf ("&ptr = 0x%x\r\n", (unsigned int)&ptr);
pointerTest (&ptr);
while(1);
} |
And I see what I expect:
Code: | ptr = 0x1072
&ptr = 0x1092
ptrPtr = 0x1092
*ptrPtr = 0x1072 |
But something is wacky with how I am dereferencing the pointer in my routine. The code worked on OS-9 with Microware's Ultra-C compiler (back in the late 90s!), Eclipse/GCC for ARM, GCC/x86, and a few others I've done this.
Can someone see something glaringly obvious I am doing wrong?
Thanks, much. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
Last edited by allenhuffman on Mon Dec 09, 2019 1:54 pm; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Mon Dec 09, 2019 2:56 am |
|
|
Your posted code compiles and runs without crashing for me.
However I can see it is likely to crash for the 16bit and 32bit versions.
Are you sure it is not these that have the problems?.
The reason is alignment. Problem is that when you try to fetch a
16bit or 32bit value using the pointer, it is a byte aligned pointer, and
has been incremented to an odd address. A fetch of a 16bit or 32bit
value, requires the pointer to be word aligned.
If it is the 16 and 32bit versions that are the crash, then the answer is to
fetch byte values and then convert these into the 16bit ot 32bit values
after fetching these. Using possibly a union or make16.
Your 'memcpy' line is different, since there is nothing called 'data' in the
function....
Just as a demo, done it using memcpy:
Code: |
void put8 (uint8_t **destPtr, uint8_t value)
{
// This doesn't work for me on the CCS compiler. - works for me
memcpy (*destPtr, &value, sizeof(value));
(*destPtr) += sizeof(value);
}
void put16 (uint8_t **destPtr, uint16_t value)
{
memcpy(*destptr, &value, sizeof(value));
(*destPtr) += sizeof(value);
}
void put32 (uint8_t **destPtr, uint32_t value)
{
memcpy(*destptr, &value, sizeof(value));
(*destPtr) += sizeof(value);
}
uint8_t get8 (uint8_t **sourcePtr)
{
uint8_t value;
memcpy(&value, *sourcePtr, sizeof(value));
(*sourcePtr)++;
return value; // TODO: add error checking!
}
uint16_t get16 (uint8_t **sourcePtr)
{
uint16_t dest;
memcpy(&dest, *sourcePtr, sizeof(dest));
(*sourcePtr) += sizeof(dest);
return dest; // TODO: add error checking!
}
uint32_t get32 (uint8_t **sourcePtr)
{
uint32_t dest;
memcpy(&dest, *sourcePtr, sizeof(dest));
(*sourcePtr) += sizeof(dest);
return dest; // TODO: add error checking!
}
|
Merrily works for me and returns the right values. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Dec 09, 2019 7:00 am |
|
|
How odd. The memcpy() for the byte always ended up with zero in the buffer, but worked fine for the others. I figured maybe you couldn’t memcpy() a byte due to the word addressing on PIC24. (Yeah, originally I had called it data, then renamed it to value but didn’t change the commented out code.)
I wonder if memcpy() has issues on odd bye alignment on PIC24. I’ll consult the manual. I didn’t consider that could be an issue.. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Mon Dec 09, 2019 7:13 am |
|
|
What compiler version are you on?.
I was testing with 5.091, and the bytes were all copied OK. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Dec 09, 2019 9:05 am |
|
|
No steps forward, one step back... When I try the "get8" using memcpy(), I get 00 as my result.
Code: |
...snip...
uint8_t buffer[32];
uint8_t *ptr = &buffer[0];
memset (buffer, 0x0, sizeof(buffer)); // edit: added this
put8 (&ptr, 0x11);
put8 (&ptr, 0x22);
put8 (&ptr, 0x33);
put16 (&ptr, 0xAABB);
put32 (&ptr, 0x12345678);
showBuffer (buffer, sizeof(buffer));
ptr = &buffer[0];
printf ("%2x ", get8 (&ptr));
printf ("%2x ", get8 (&ptr));
printf ("%2x ", get8 (&ptr));
printf ("%2x ", get16 (&ptr));
printf ("%2x ", get32 (&ptr));
printf ("\r\nDone...");
...snip... |
Code: | 11 22 33 bb aa 78 56 34 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00 00 00 aabb 12345678
Done... |
_________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Mon Dec 09, 2019 9:15 am |
|
|
Your get16, and get32 lines both need %Lx not %x or they will only
print the low byte fetched. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Dec 09, 2019 9:27 am |
|
|
Ttelmah wrote: | Your get16, and get32 lines both need %Lx not %x or they will only
print the low byte fetched. |
Good point - I'll correct that (though it does print as expected in my case). I also copy/pasted just %02x (two digits) when I wanted 4 and 8.
The only one I am having issues with is the memcpy() of the 8-bit value. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Dec 09, 2019 10:17 am |
|
|
I think I have gremlins. Now the put32 is not working, same code I was using when I posted the previous message with the hex dump. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Dec 09, 2019 10:27 am |
|
|
Ttelmah wrote: | Your get16, and get32 lines both need %Lx not %x or they will only
print the low byte fetched. |
I see their implementation of printf is different. I used %2x and it gave me 00, where normally you have to specify %02x to get leading zeros if the value is less than 0x10. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Dec 09, 2019 12:21 pm |
|
|
Can someone explain this? I have three test functions that are identical, except for the data type of the second parameter:
Code: | void test8 (uint8_t **destPtr, uint8_t value)
{
printf (" destPtr = 0x%lx\r\n"
"*destPtr = 0x%lx\r\n"
" value = %lx\r\n", destPtr, *destPtr, value);
}
void test16 (uint8_t **destPtr, uint16_t value)
{
printf (" destPtr = 0x%lx\r\n"
"*destPtr = 0x%lx\r\n"
" value = %lx\r\n", destPtr, *destPtr, value);
}
void test32 (uint8_t **destPtr, uint32_t value)
{
printf (" destPtr = 0x%lx\r\n"
"*destPtr = 0x%lx\r\n"
" value = %lx\r\n", destPtr, *destPtr, value);
} |
The body of each function is a copy/paste. Only the data type of the "value" parameter is changed.
Yet somehow this changes the value of "*destPtr":
Code: | uint8_t buffer[25];
uint8_t *ptr;
ptr = &buffer[0];
test8 (&ptr, 1);
test16 (&ptr, 2);
test32 (&ptr, 3); |
I know it has to be a compiler quirk, since changing a second parameter should not affect the first, but this seems to be the root cause of my issue. It seem to be dereferencing a bad address and writing data somewhere bad and causing my crash. What's odd is that, when I ran it to capture the output, it showed the 16 version working, and 8 and 32 not. But in my real code, it's the opposite. The difference here is that ptr is not being moved, so it's always even. In my test code, the u8 is even, the u16 and u32 are odd, and the u16 is not working but the other two are.
Madness
Code: | destPtr = 0x108e
*destPtr = 0x74
value = 1
destPtr = 0x108e
*destPtr = 0x1074
value = 2
destPtr = 0x108e
*destPtr = 0x74
value = 3 |
_________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 09, 2019 12:56 pm |
|
|
What is your compiler version ? You rarely tell us. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Dec 09, 2019 1:24 pm |
|
|
It looks like I needed to nudge the compiler a bit more to make it understand what I wanted:
Code: | void put32 (uint8_t **destPtr, uint32_t value)
{
memcpy (&(*destPtr)[0], &value, sizeof(value));
(*destPtr) += sizeof(value);
} |
But using "&(*destPtr)[0]" instead of just "(*destPtr)" it seems to work in all my test cases.
At the moment. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Dec 09, 2019 1:25 pm |
|
|
PCM programmer wrote: | What is your compiler version ? You rarely tell us. |
5.091 -- see my 7:30am post.
I always run the latest for new code development, and only revert if I find a compiler issue that requires it.
Our production code uses an older version, but since this is all-new code that will be fully validated and tested on its own, I'm working with the latest.
EDIT: Incidentally, from my days at doing support for an embedded OS company, the first thing we'd always ask is "are you using the current version?" and go from there, so I've kinda just got in the habbit of doing that myself. If there's a bug in an old version I use, but it works in the new, then it's my bad for not updating _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Dec 09, 2019 1:53 pm |
|
|
Here is my final "working" functions, and my mini-test suite function for it, as well as a "passing" output:
Code: | uint8_t get8 (uint8_t **sourcePtr);
uint16_t get16 (uint8_t **sourcePtr);
uint32_t get32 (uint8_t **sourcePtr);
void getData (uint8_t **sourcePtr, uint8_t *destPtr, unsigned int destSize);
void put8 (uint8_t **destPtr, uint8_t value);
void put16 (uint8_t **destPtr, uint16_t value);
void put32 (uint8_t **destPtr, uint32_t value);
void putData (uint8_t **destPtr, uint8_t *sourcePtr, unsigned int sourceSize);
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h> // memcpy ()
uint8_t get8 (uint8_t **sourcePtr)
{
uint8_t value;
memcpy(&value, &(*sourcePtr)[0], sizeof(value));
(*sourcePtr) += sizeof(value);
return value;
}
uint16_t get16 (uint8_t **sourcePtr)
{
uint16_t value;
memcpy(&value, &(*sourcePtr)[0], sizeof(value));
(*sourcePtr) += sizeof(value);
return value;
}
uint32_t get32 (uint8_t **sourcePtr)
{
uint32_t value;
memcpy(&value, &(*sourcePtr)[0], sizeof(value));
(*sourcePtr) += sizeof(value);
return value;
}
void getData (uint8_t **sourcePtr, uint8_t *destPtr, unsigned int destSize)
{
memcpy (destPtr, &(*sourcePtr)[0], destSize);
(*sourcePtr) += destSize;
}
void put8 (uint8_t **destPtr, uint8_t value)
{
memcpy (&(*destPtr)[0], &value, sizeof(value));
(*destPtr) += sizeof(value);
}
void put16 (uint8_t **destPtr, uint16_t value)
{
memcpy (&(*destPtr)[0], &value, sizeof(value));
(*destPtr) += sizeof(value);
}
void put32 (uint8_t **destPtr, uint32_t value)
{
memcpy (&(*destPtr)[0], &value, sizeof(value));
(*destPtr) += sizeof(value);
}
void putData (uint8_t **destPtr, uint8_t *sourcePtr, unsigned int sourceSize)
{
memcpy (&(*destPtr)[0], sourcePtr, sourceSize);
(*destPtr) += sourceSize;
}
void testGetPutData()
{
uint8_t buffer[25];
uint8_t *ptr;
uint8_t u8data[] = { 0x11, 0x22, 0x33 };
uint16_t u16data[] = { 0xaabb, 0xccdd, 0xeeff };
uint32_t u32data[] = { 0x12345678 };
memset (buffer, 0x0, sizeof(buffer));
ptr = &buffer[0];
showBuffer (ptr, sizeof(buffer));
// write u8 data
for (unsigned int idx=0; idx < sizeof(u8data)/sizeof(u8data[0]); idx++) put8 (&ptr, u8data[idx]);
// write u16 data
for (unsigned int idx=0; idx < sizeof(u16data)/sizeof(u16data[0]); idx++) put16 (&ptr, u16data[idx]);
// write u32 data
for (unsigned int idx=0; idx < sizeof(u32data)/sizeof(u32data[0]); idx++) put32 (&ptr, u32data[idx]);
// write arbitrary sized data
putData (&ptr, &u8data[0], sizeof(u8data));
// Verify
ptr = &buffer[0];
showBuffer (ptr, sizeof(buffer));
for (unsigned int idx=0; idx < sizeof(u8data); idx++)
{
uint8_t data = get8 (&ptr);
if (data != u8data[idx]) printf ("BAD! ");
printf ("u8 %u. read %u, expected %u\r\n", idx, data, u8data[idx]);
}
for (unsigned int idx=0; idx < sizeof(u16data)/sizeof(u16data[0]); idx++)
{
uint16_t data = get16 (&ptr);
if (data != u16data[idx]) printf ("BAD! ");
printf ("u16 %u. read %lu, expected %lu\r\n", idx, data, u16data[idx]);
}
for (unsigned int idx=0; idx < sizeof(u32data)/sizeof(u32data[0]); idx++)
{
uint32_t data = get32 (&ptr);
if (data != u32data[idx]) printf ("BAD! ");
printf ("u32 %u read %lu, expected %lu\r\n", idx, data, u32data[idx]);
}
uint8_t inBuffer[sizeof(u8data)];
getData (&ptr, &inBuffer[0], sizeof(inBuffer));
if (memcmp (inBuffer, u8data, sizeof(inBuffer)) != 0) printf ("BAD! ");
printf ("data read: ");
showBuffer (inBuffer, sizeof(inBuffer));
printf ("expected:");
showBuffer (u8data, sizeof(u8data));
} |
OUTPUT:
Code: | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
11 22 33 bb aa dd cc ff ee 78 56 34 12 11 22 33 00 00 00 00 00 00 00 00 00
u8 0. read 17, expected 17
u8 1. read 34, expected 34
u8 2. read 51, expected 51
u16 0. read 43707, expected 43707
u16 1. read 52445, expected 52445
u16 2. read 61183, expected 61183
u32 0 read 305419896, expected 305419896
data read: 11 22 33
expected:11 22 33 |
(Yeah, the output could be made a bit nicer; printing hex and such.)
Thanks for everyone's help here! _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|