Page 1 of 1

pointers getting nutz !

Posted: Thu Jan 13, 2005 7:34 pm
by evilo
I currently have some strange behaviour with pointers to different data types ..

So le'ts try to explain myself as simple as possible ! let's say that I have one function with the following prototype :
void* get_something(_u32 parameter);
And that can return a pointer to either a u8, u16, u32 (depeding of the case, and this is not the case in which the returned value type is not the exptected one), Then this fct is called by an other one like :
_u16 myFct(_u32 parameter)
{

_u16* ptr = get_something(parameter);

if (ptr == NULL)
return 0;
else
return *ptr;
}
In the above case the expected return value is a u16, so it should work, but calling it result in garbages in *ptr, and only a bad hack like the following one allow to get the correct return value....
Casting have no effect, and compiler keep complains on "casting pointers from different sizes" if I cast it.
_u16 myFct(_u32 parameter)
{

_u8* ptr = get_something(parameter);

if (ptr == NULL)
return 0;
else
return ptr[1]<<8|ptr[0];
}
So just declaring it as a u8...

I have similar fct that are waiting for a u8 and u32...
only _u8 is working fine, as it "seems" to be the only possible things returned, but for _u32 value, the only way to make it working is to apply the same kind of stuff that above...

What is the problem ?? This code is working just fine when compiled and ran on a PC..

Is it me, or is there any issue with pointer in the GCC, SDK ??

thanks..

Posted: Thu Jan 13, 2005 8:01 pm
by pixel
It all depends on what your "void *" is pointing at. You have to know something: on MIPS processors, memory access (load and store) has to be aligned. That is:

Code: Select all

u8 tab&#91;6&#93; = &#123;1, 2, 3, 4, 5, 6&#125;;
u32 * p = &tab&#91;2&#93;;
u32 a = *p;
This piece of code will perfectly work on any x86, but won't on PS2. Most probably will generate an exception though, instead of having a random behavior like you're experiencing.

Posted: Thu Jan 13, 2005 8:06 pm
by Guest
Try return (_u16)*ptr;

Pixel, are you sure alignment is the issue here ? I thought the compiler should automatically generate instructions to handle unaligned load/stores ?
I am wondering that it simply isn't casting the return value properly.

If alignment was the issue, then a bus-error should be generated.

But the problem is certainly due to each architectures native word size and unaligned load/store handling. :) But should be able to code a program around that.

Posted: Thu Jan 13, 2005 8:10 pm
by evilo
That's exactly the kind of stuff done inside the function...

hmm... I didn't know that memory aligment was also applying in this case..

is there any workaround, except the one I used (shtg more clean) ??

thanks for your answer.

Posted: Thu Jan 13, 2005 8:19 pm
by Guest
evilo wrote:That's exactly the kind of stuff done inside the function...

hmm... I didn't know that memory aligment was also applying in this case..

is there any workaround, except the one I used (shtg more clean) ??

thanks for your answer.
Did you try what I suggested ?

The alignment issue here is how the compiler by default does casting (or lack thereof) when moving the return value from your function (32 bits) to the u16 variable (16 bits).

Posted: Thu Jan 13, 2005 8:21 pm
by evilo
yes sorry gorim...
_u16* ptr =(_u16* ) get_something(parameter);
if (ptr == NULL)
return 0;
else
return (_u16)*ptr;
the effect is the same... I get it back as a u8 but casted to u16 ...

Posted: Thu Jan 13, 2005 8:25 pm
by Guest
I bet the problem is inside get_something()....


code code! show me!

Posted: Thu Jan 13, 2005 8:31 pm
by evilo
lol... :)
id* translate_address_read(_u32 address)
{
address &= 0xFFFFFF;


if (address == 0x8008)
ram[0x8008] = (_u8)((abs(TIMER_HINT_RATE - (int)timer_hint)) >> 2);

if (address <= RAM_END)
return ram + address;

// ===================================

//Get EEPROM status?
if (eepromStatusEnable)
{
eepromStatusEnable = FALSE;
if (address == 0x220000 || address == 0x230000)
{
eepromStatus = 0xFFFFFFFF;
return &eepromStatus;
}
}

//ROM (LOW)
if (rom.data && address >= ROM_START && address <= ROM_END)
{
if (address <= ROM_START + rom.length)
return rom.data + (address - ROM_START);
else
return NULL;
}

//ROM (HIGH)
if (rom.data && address >= HIROM_START && address <= HIROM_END)
{
if (address <= HIROM_START + (rom.length - 0x200000))
return rom.data + 0x200000 + (address - HIROM_START);
else
return NULL;
}

// ===================================

//BIOS Access?
if ((address & 0xFF0000) == 0xFF0000)
return bios + (address & 0xFFFF); // BIOS ROM

// ===================================

//Signal a flash memory error
if (memory_unlock_flash_write)
memory_flash_error = TRUE;

return NULL;
}
ram is declared as _u8 ram[]
eepromStatus is delacred as _u32;

code is working like a charm on pc, and this is typically the case that pixel showed before.. I don't think there is any clue apart rewriting the code in a completely different way..

Posted: Thu Jan 13, 2005 8:42 pm
by Guest
Where exactly in the code is eepromStatus declared ?

I see you returning &eepromStatus. If it is declared inside the function, you are returning a pointer to the stack and that will be corrupted surely. The only way to prevent that is to declared eepromStatus statically or outside of any function. Since stack corruption manifests in weird and random ways, its quite likely it can work fine on a PC but fail elsewhere.

Other than that, not sure what the rom structure looks like, but nothing else looks obviously wrong. :)

Posted: Thu Jan 13, 2005 9:15 pm
by evilo
eepromStatus is a global static variable,

rom.data is a u8 array

hmm ;)

Posted: Fri Jan 14, 2005 3:05 am
by J.F.
Two things:

1 - What is the address when it goes bonkers? Maybe it is an alignment issue.
2 - Why don't you just look at the generated code?

For 1, look at it this way. The value is a pointer. How is the code supposed to know what it will be? If the address is a constant like a variable address, code to handle unaligned access can be generated. However, there's no way to do that with a pointer. YOU have to do that.

u16 access_word(u16* address) {
if ((u32)address & 1) {
u8 *ptr = (u8*)address;
return (u16)(ptr[1]<<8 | ptr[0]);
} else
return *address;
}

See? YOU handle the alignment yourself because YOU can determine the alignment where the compiler can't.

Posted: Fri Jan 14, 2005 3:30 am
by mrbrown
Yes, just post the assembly of the function, so folks will stop trying to guess at what's going on.

And here someone told me not too long ago that knowing asm for the CPU you're dealing with isn't important :P.

Posted: Fri Jan 21, 2005 12:55 pm
by dreamtime
Did you guys work out what the problem with this was?
I think I remember having similar problems around 2 years ago and came up with a solution :)
I'd need to see exactly how all your globals are declared.