gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Behavioral changes in int casting

#74184 - MrAdults - Fri Mar 03, 2006 8:26 am

I was using devkitPro r14, and I'm modifying my project to work with r17. I have one particular function that is showing very different results. It may not be completely clear out of context, but here is the function:

Code:
int W_CheckNumForName(char *name)
{
   char name8[9];
   int v1, v2;
   lumpinfo_t *lump_p;

   // Make the name into two integers for easy compares
   strncpy(name8, name, 8);
   name8[8] = 0; // in case the name was a full 8 chars
   strupr(name8); // case insensitive
   v1 = *(int *)name8;
   v2 = *(int *)&name8[4];

   // Scan backwards so patch lump files take precedence
   lump_p = lumpinfo+numlumps;
   while(lump_p-- != lumpinfo)
   {
      if(*(int *)lump_p->name == v1 && *(int *)&lump_p->name[4] == v2)
      {
         return lump_p-lumpinfo;
      }
   }
   return -1;
}


So, there are a few things you could see possibly going wrong here, such as the incoming string being 6 characters and the stack array not being zero'd out, or whatever. That is not happening - byte for byte, all 8 bytes from the name8 memory address and from the lump_p->name memory address match up. Additionally, both addresses are 4-byte-aligned.

The problem is that whatever code is generated by those *(int *)lump_p->name statements is not doing what it was doing in r14, so the ints are actually different values despite being cast from 2 identical and aligned 8-byte memory chunks. I could write some inline assembly to ldr and compare manually, but I would really prefer not to. Does anyone know why this would be different all of a sudden?

-Rich

#74261 - sajiimori - Fri Mar 03, 2006 9:57 pm

Working on a Doom port? :)

If you've already put in asserts on the alignment of name8 and every lump_p->name address, the next step is to compile the code with -S on each version of the compiler and see what's different.

Nothing about the code stands out to me other than alignment.

#74295 - MrAdults - Sat Mar 04, 2006 4:59 am

Yeah, I guess copying addresses by hand into calc.exe at 2am isn't a good idea. The stack address was not 4-byte-aligned after all. Thanks for the reply anyway. :)

Although I am curious, was something related to stack alignment changed between r14 and r17, or did the change in crt/lib/whoknowswhatelse code just happen to push the location of my stack variable off by a couple bytes?

-Rich

#74296 - DekuTree64 - Sat Mar 04, 2006 5:01 am

Huh, I thought it was ARM standard that the stack pointer always be word aligned. Maybe should be reported as a bug in the latest GCC.

Probably what's causing it is that array of 9 chars. Try rounding it up to 12, just as a workaround, and see if it works.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#74297 - MrAdults - Sat Mar 04, 2006 5:16 am

Yeah, padding that from 9 to 12 corrects the issue. Looking at the generated assembly for the unpadded version I can see the problem pretty quickly:

Code:
   sub   sp, sp, #12
.LCFI7:
.LVL43:
   .loc 1 474 0
   add   r4, sp, #3


Apparently it decided to pad that array, but instead of giving me a pointer to its base, it gave me a pointer to padded size minus the size of the array. Silly compiler.

-Rich

#74305 - GPFerror - Sat Mar 04, 2006 6:25 am

how do you pad a struct for that?

iv had a similiar issue, where i was trying to load data into a structure member and it was using sizeof(structmem) and i had to change it to a hardcoded value that i got from the pc version of the port.

thanks,
Troy(GPF)
http://gpf.dcemu.co.uk

#74307 - MrAdults - Sat Mar 04, 2006 6:46 am

That's a somewhat different matter than what's discussed above (seems that stack alignment should be handled automatically and properly by the compiler, even though it isn't with the latest GCC). By default all of your structs will be 4-byte/word-aligned, and sizeof will be the padded size. If you want to avoid having unknown pad added to your structs you can just add pad members yourself to make sure everything is 4-byte-aligned. You can also disable struct alignment with a compiler option, but on the DS that would be a generally bad idea.

-Rich

#74312 - sajiimori - Sat Mar 04, 2006 7:37 am

Maybe I wouldn't blame GCC for not aligning a char array (since it might expect you to only use byte operations), but it does seem odd that it chose to start the array on an unaligned address even though it made enough space to use an aligned address.

#74315 - MrAdults - Sat Mar 04, 2006 8:02 am

I would be less inclined to blame the compiler, except for the GCC included with devkitPro r14 also pads that array to 12 bytes (took a look at the assembly for that version as well), but doesn't add the extra 3 bytes back, and rather just gives me the base. It's definitely odd behavior, and it wasn't there before.

-Rich

#74316 - DekuTree64 - Sat Mar 04, 2006 8:18 am

I think the 4 byte alignment is to conform to the standard, but it wants to squeeze the 9 byte array up as high as possible so if you do happen to make another byte variable, it can go in those 3 bytes below instead of allocating another 4 bytes.
While there is some logic to that, I'd rather it sacrifice that bit of extra space to have correct alignment for faster mem copies and such. At least there should be an option for it, rather than just changing the behavior entirely.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku