Overlapping Variables Make Me Cry

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Overlapping Variables Make Me Cry

2,543 Views
JohnPassaniti
Contributor I

I'm using CodeWarrior 5.9.0 for a HCS08 target.  I'm new to CodeWarrior, so please be gentle.

 

I have an application which has two interrupt service routines in two different source files.  Both source files have variables used by the ISRs at file scope.  When linked, the linker is apparently determining that these variables can be overlaid (they are appearing in a .common segment instead of .bss).

 

While I'm delighted that the linker is apparently reviewing the call graph of my application and trying to optimize, it's getting it wrong, and I can't figure out how to simply tell the linker to not try to make this optimization at all.  Maybe later, I'll fine-tune it and delight in the amount of RAM saved.  Right now, I want the linker to not try to be clever.

 

Thanks for any advice.

Labels (1)
Tags (1)
0 Kudos
8 Replies

1,234 Views
CompilerGuru
NXP Employee
NXP Employee

I don't think there is such an optimization for the current S08 tools...

The only time variables are overlayed in C is if they have external linkage and the same name, is this the case?

Can you show how you defined the variables?

How does the map file look like? Do they have the same name, are they static?

 

Daniel

 

BTW: The is a similar setup for local variables (not file scope) for the RS08 (and HC05). I assume above that this issue is really for a S08, and not a RS08.

 

0 Kudos

1,234 Views
JohnPassaniti
Contributor I

Yes, this is for a HCS08.

 

There is definately some data overlaying going on, and the documentation talks about this.  It specifically talks about overlaying parameters (and probably locals).  Maybe the intent is to support processors like the RS08, but I'm guessing that if they support it for the RS08, then they probably support it for other non-RS08 targets as well.

 

I'll gladly provide a test case if necessary, but really, all I want is whatever incantation turns this optimization off.  I know it's happening because when I look in the application's map file, I see variables in a section named ".common" that have overlapping addresses.  If you only know of this optimization in the context of a RS08, then fine... if there is a way to disable it for that target, give me that.

 

Thanks.

 

 

 

 

0 Kudos

1,234 Views
CompilerGuru
NXP Employee
NXP Employee

For the RS08 case it is not an optimization, it is the default (and only) way local variables and parameters are allocated, as the RS08 has no stack pointer.

Your issue with .bss/SHN_COMMON has nothing to do with the overlapping for the locals and parameters the linker manual talks about. My guess is that in your case it is a reuse of a name. Please check if the "reused" objects have the same name and if they are static or external. Using in two C files a global "int i;" will cause the two i to be "overlapped". The quotes are because the C language treats them as the same object (with 2 tentative definitions), so its not actually overlapping different objects, its the same object.

Well either way, with the linker overlapping support you are on the wrong track.

 

For the S08, please provide a test case.

 

Daniel

 

0 Kudos

1,234 Views
Stryphe
Contributor II

Howzit

 

I was / am having a similar problem. I am also using FreeScale CodeWarrior (6.2) 5.9 IDE on an HCS08 (MC9S08LL16) (came with the demo kit). I have tried updating with latest patches, and the 6.2.2 patch, to no avail.

 

My intial problem that sounds similar to yours, was that I found that a global variable which was being read from both inside an ISR and in normal function blocks, was being affected / changed somehow, even after commenting out all lines of code used to change it. I.e. Impossible state changes. It was initially solved by making the global variable static, preventing outside changing of it or altering of it. But effectively all that did was move the code variables a little higher up in RAM, inside the .bss block, from the .common block.

 

Now .bss is for global or initialised variables where .common is for non global and non initialised variables. But I find myself in the situation later on after adding a lot more code, that other variables are being affected in a similar fashion somehow. These variables however are not being accessed by any ISR's. I have moved all of my global variables to .bss by making them static and even tried initialising them also, removing everything from the .common block thinking this might help.

 

Despite that, I still I find myself in the situation where I have narrowed the code down to a small set of global variables where the code is operational, but when I REMOVE one or two variable's declaration, or even the line of code that uses them, it shifts everything down in RAM and the code fails. Now if it's a positional thing: I have moved around where the RAM section starts and still fails. So it's a relative / positional thing or is just assigning overlaps. But I have scoured the map file and can't find / see any overlaps. Comparing the map file from the working versions and the ones that fail, the only difference is the RAM shifted down 4 or 5 bytes from the point of the removed variable.

 

I should point out at this stage that it compiles each time and that it is at run-time that I see the problem, as the operation of my RToS fails, by the adding / removing of unrelated variables which don't physically affect / control anything which fails as a result of changing them. In other words: I have a set of blocks that individually work perfectly, but certain combinations of them causes them to all fail. Specifically this block mentioned above, making me investigate its variables and their declaration / position.

 

I had thought it possible that the linker only allows a certain length of variable name before it thinks it's the same variable, but I can see each individual variable name and their position in RAM under the "OBJECT LIST SORTED BY ADDRESS" in the map file.

 

I have tried increasing the stack and the zero_page size allocation to obscenely large amounts to fill up the RAM to the 2k RAM limit, and have filled the ROM with other working code blocks to the brink of the 16k ROM limit, and the code works just fine.I have also tried taking the working code that is very close to the fail code and dropping the stack and zero page to absolute minimums, and they continue to work. This all leads me to believe it to be something to do with the compiler and or the allocation of certain memory.

 

Any assistance welcome...

Jacques

0 Kudos

1,234 Views
bigmac
Specialist III

Hello Jaques,

 

If not a stack overflow problem, perhaps you have a wayward pointer within your code.  It is possible that a pointer problem may affect only a small range of RAM.

 

Regards,

Mac

 

0 Kudos

1,234 Views
Stryphe
Contributor II

Hi Guys

 

Thanks for the suggestions.

 

Well I don't feel it's the stack because with all the blocks of code in, it runs on a stack as small as 80bytes. But if I put the stack up to 512bytes, it doesn't solve anything. As far as I am aware, there is only one stack.  But I may be wrong. This is my working PRM file:

// ------------------------------------------------------------------------------------------------------------ //
NAMES END
SEGMENTS
    Z_RAM                    =  READ_WRITE   0x0060 TO 0x01FF;
    RAM                      =  READ_WRITE   0x0200 TO 0x087F;
    ROM                      =  READ_ONLY    0xC000 TO 0xFFBF;
    ROM1                     =  READ_ONLY    0xFFC0 TO 0xFFD7;
END

PLACEMENT
    DEFAULT_RAM,                        /* non-zero page variables */
                                        INTO  RAM;
    _PRESTART,                          /* startup code */
    STARTUP,                            /* startup data structures */
    ROM_VAR,                            /* constant variables */
    STRINGS,                            /* string literals */
    VIRTUAL_TABLE_SEGMENT,              /* C++ virtual table segment */
    DEFAULT_ROM,
    COPY                                /* copy down information: how to initialize variables */
                                        INTO  ROM; /* ,ROM1: To use "ROM1" as well, pass the option -OnB=b to the compiler */
    _DATA_ZEROPAGE,                     /* zero page variables */
    MY_ZEROPAGE                         INTO  Z_RAM;
END

STACKSIZE 0x100  

VECTOR 0 _Startup /* Reset vector: this is the default entry point for an application. */
// ------------------------------------------------------------------------------------------------------------ //


As for wayword pointers, I'm starting to agree with you, since it's a relative position in memory each time, irrespective of me shifting around where the RAM starts.

 

I managed to get all the code "working" yesterday by removing all intialization of global variables except for arrays / structs, and removed all static declarations to non arrays / structs. As a result, the LED task that was having a problem yesterday now works fine, but my RS232 comms task now is faulty as it buffers wrong. However, removing all the other blocks of code no longer fixes it, where doing so did fix the LED task yesterday.


I am mainly using arrays and structures as follows:
   static int bob[boblength] = {0, 1, 2, 3};

etc. where the calls to the arrays are in for loops with:

   intTemp = bob[loopvariable];
or
   if (bob[loopvariable] == constant) <action>

 

Though, I have two pointers, used in my functions to draw a string on my LCD and to convert a 16bit integer to a string (the string.h and strcat functions took up far too much ROM so I wrote my own hehe).

 

   void io_LCD_putstring(byte* str2draw)

   void io_WordToStr(byte* str, byte len, word val)

but every call to it passes a constant "12345" or mmm. You may have a point.
I am also passing it variables designed to save ROM space, since I have ample RAM. So I was sending it pseudo constants as follows:


// ------------------------------------------------------------------------------------------------------------ //
typedef struct
{
  byte str[menudisplaystrlengthmax];
} menu_display;

static menu_display io_sMenuDisplay_EXIT = {"EXIT"};
// ------------------------------------------------------------------------------------------------------------ //

 

The comms (unrelated to above) was sending 1 of the 2 packets, and that one packet was not syncing correctly without static.(i.e. of it's 3 bytes, it would send 2,3,1 instead of 123, confirmed by serial port monitor). Now, making the variable "static", I see that the comms of that packet is correct again, sending (1,2,3). Wierd since it stores those variables in the same place in .data whether you make them static or not. So the question now is, why is this static variable stored in .data and not in .bss? .data is still stored in RAM, but how is it different to .bss?

 

I am able to "hide" the bug by moving allocations around with static changes, but I am not confident that I have eliminated the bug, or grasping what is / was causing my problems in the first place. Do you think it could be related to these functions being passed pointers as an argument and not being passed a const / static ?

 

Thanks for your suggestions :smileyhappy:

Regards,

Jacques

 

0 Kudos

1,234 Views
Stryphe
Contributor II

Hey guys :smileyvery-happy:

 

Hmmm. I think I may have fixed it after all, if not hidden it somewhere else haha.

 

The static on the many:

   static menu_display io_sMenuDisplay_EXIT = {"EXIT"};

strings synced the comms correctly , and serial monitor shows correct comms now.


I also found a local variable initialisation left:

   byte strtmp[displaystrlengthmax]= "";

which was promptly changed to:

   byte strtmp[displaystrlengthmax];

and since I do all the manipulation myself, I don't need it to be blank or even null pointed.

 

So all blocks for now appear to be running smoothly and glitch free. I hope this was the memory overwrite after all.

 

Then, and this is completely unrelated to the post, but getting the comms to work: (skip this if uninterested)

 

My serial comms runs at 57600 and I send 6 bytes every 20ms. The problem I had with my serial port was that when I sent a packet of 3 bytes every 20ms, it used to get every 2nd packet of 3. So I doubled up each packet into 6 and send the same thing twice. I.e. packet1, packet1, wait 20ms, packet2, packet2, wait 20ms. (11, 22, 11, 22etc)

 

Now this has been working with my serial port for a while now. (serial monitor confirms the port only getting packet1, packet2, packet1, packet2, etc and not doubling up). I presumed the serial port was just too slow. (I need to send the data that fast, for resolution, and I can't afford to buffer up a whole bunch and send because I can't send more than 6-8 bytes at a time in every 10ms period due to a periodic clock interrupt and other tasks that need to happen).

 

So now with this glitch, it was only getting packet2, over and over and over. Never seeing packet1. After fxing the variable declaration above, serial monitor confirmed both packet1 and packet2 going through, but my software reading it on the PC side still only saw the 2nd packet (222222etc).

 

Changing the comms dump from 11,22,11,22etc to 12,12,12,12 to see if it would somehow now be fast enough resulted in the serial port seeing 1212 but the software now only seeing the 1st packet (1111etc).  Amusing.

 

So I changed it to 12,21,12,21etc and the software sees both happily (121212etc), as well as the port monitor seeing 1212etc.

 

Does that make sense? Who cares... it's working... lol.

 

0 Kudos

1,234 Views
CompilerGuru
NXP Employee
NXP Employee

Well sounds to me like a stack size issue. Does the OS have multiple stacks? Did you increase all of them?

Another source are non initialized (local) variables, programming bugs.

 

As some globals get overwritten from a unknown location, I would try to add a global which is never written into the problematic area and then set a write watchpoint on that variable, then wait and see who writes it anyway.

Does it overwrite a single variable or a whole memory area?

 

Try filling all the memory upfront with some pattern to see if any of the stacks are full/nearly full.

 

Daniel

0 Kudos