Topic : va_arg and vsprint issues running above address space 0x00FFFF

Forum : ST7/STM8

Original Post
Post Information Post
October 22, 2012 - 5:22am
Guest

All the following code I am trying to execute from an address space above 0x00FFFF. All the functions that would normally be forced memory below 0x00FFFF have been redirected above 0x00FFFF using the linker workaround lxf file.

I have tried the same routines in a test program that executed all code below 0x00FFFF and it worked ok. But I need to get it working above 0x00FFFF.

I have a function that I am using an args list with. The prototype looks like this:


int SerialDebug_QueueMessage(char *messagetosend,...);

I'm then using va_start then vsprintf, then va_end; The routine never returns from the vsprintf and causes the microcontroller to reset. I stepped through the assembly and found that inside vsprint, there appear to be some jumps to addresses where the address is being calculated just prior to the jump. Unfortunately, it appears some pointer is incorrect and I think it tries to jump to an illegal address.

I began to wonder if it was because the argument list was wrong.

I set it up so that I was passing a known value of a known type (uint8_t) into the function's args list.
I changed the code to add the following between va_start and vsprintf:


ui8val=va_arg(arglist,uint8_t);

ui8val doesn't get populated with the correct value.

At the end of the following piece of STVD assembly readout code from va_arg, the pointer is one byte off the correct byte's address.

I'm suspiscious of the line LDW(0x9e,SP),X. Is this offset computed at compile time or has an assumption been made about how stdarg will be used and the offset is static? Is it the extra byte on the stack for the 24 bit CALLF address that has shifted it one byte out of place? or something else?


SERIALDEBUG.C:115        ui8val=va_arg(arglist,uint8_t); 
0x173b8 <._QueueMessage+144> 0x1F9E          LDW   (0x9e,SP),X         LDW   (0x9e,SP),X 
0x173ba <._QueueMessage+146> 0x5A            DECW  X                   DECW  X 
0x173bb <._QueueMessage+147> 0xF6            LD    A,(X)               LD    A,(X) 
0x173bc <._QueueMessage+148> 0xC70061        LD    0x0061,A            LD    ui8val,A 


I'd really like to use the formatting of vsprintf. If vsprintf wont work for us, we could write our own version but we would need vargs to work properly.

Replies
Post Information Post
+1
0
-1
October 22, 2012 - 4:11pm
Raisonance Support Team

Hello John,

vsprint like all library routines don't support "far data", they all except data located below 0x10000 (16 bits).
For large object access, please refer to 7.7 Large objects access functions in the ST7/STM8 C Compiler Manual
See also 4.8.1 STM8 large memory model

Otherwise,

When a char is passed through '...' it is promoted to int (that's the reason why the pointer is one byte off the correct byte's address), so you should pass 'int' not 'char' to 'va_arg' as in:
ui8val=va_arg(arglist,uint16_t);

Regarding LDW(0x9e,SP),X:
0x9e is the offset in the stack of your local variable arglist and it means that you have at least 158 bytes of local variables!

vargs works properly, but you have to write your own vsprintf that properly handles 24 bit pointers.

Regards,

Stéphane

+1
0
-1
October 23, 2012 - 8:37am
Guest

Thanks for your prompt reply.

That's quite a novice mistake for me regarding the arglist and variables being promoted to int16 or uint16. Thanks for the advice. Can 32 bit variables and far pointers be passed in to the list (I haven't tried yet. )?

The stack is populated fairly heavily due to temporary strings. The strings are there to copy bytes from a far data addressed string to a temporary string on the stack that can then be passed to vsprintf as 16bit addressing. I'm not convinced that the app needs a memory manager. And I didn't really want to have the temp string(s) as global variables.

Regarding the stack, will there be an issue if a function needs to do work on a variable greater than 256 bytes away from the Stack Pointer? Ive got 400 bytes set aside for stack. My RAM globals finish well before the end of reserved stack space. Stack running into global ram variables is very unlikely at this point

For vsprintf, I'm not passing in far data to vsprintf.Byt the time i get to invoking vsprintf, the whole string exists on the stack, However, just as an experiment, I did make it a global RAM variable and it didn't make a difference.

Now that I've been set straight about the stdarg usage, It's obvious, the arglist is fine, so let me show you now where the actual crash happens in vsprintf. As I said vsprintf is doing a jump based on some calculation.

Unfortunately the calculation of the address to jump to assumes that vsprintf is executing in a space below 0x10000. It is not the only 16 bit absolute jump in the routine. The immediate addressing absolute jumps are ok because the PC just changes the lower 16 bits and it does jump to what I assume is the correct address. Those could be a problem if the code was executing across a 0x10000 or 0x20000 boundary. The line that it crashes on uses JP (X). Unfortunately because of the 16 bit address calculation, X ends up with 0 in it, so it tries to jump to 0x10000. There is nothing at 0x10000. My code begins at 0x13000.

I hope the following snippet without context is useful:


0x15b30        0x2503          JRC   0x15b35             JRC   0x15b35 
0x15b32        0xCC5C32     JP    0x5c32                 JP    0x5c32 
0x15b35        0x58              SLLW  X                       SLLW  X 
0x15b36        0x1C5B3B      ADDW  X,#0x5b3b      ADDW  X,#0x5b3b 
0x15b39        0xFE              LDW   X,(X)                  LDW   X,(X) 
0x15b3a        0xFC              JP    (X)                        JP    (X) 

John Dowdell

+1
0
-1
October 23, 2012 - 3:20pm
Raisonance Support Team

Hello John,

In the next release, va_arg will automatically treat char as int.
For 32 bit variables, it is okay, but for far pointer: currently not. I'm looking at it.

Default code generation is for stack smaller than 256. If you want to use more data on your stack use the LARGESTACK compiler directive (4.6.3 Local variables memory space qualifiers in the ST7/STM8 C Compiler Manual)

For the vsprintf, the snippet shows a C switch using a jump table. What would be interesting is the value of X (before the
SLLW as it is the index in the table) and the code after the JP (X) that contains 7 destination addresses (the jump table).

Stéphane

+1
0
-1
October 24, 2012 - 2:52pm
Raisonance Support Team

John,

I had another look at your vsprint snippet and I was able to reproduce the issue.
It comes from the fact that the code made to retrieve the destination address acts only on 16 bits whereas we are dealing with 24 bit addresses.

The code:

ADDW  X, @table
LDW   X, (X)
JP    X,(X)

is now replaced (when using large memory model) by the fat but always true:

PUSHW X
LD    A,#HIGH24(?LAB_0003)
LD    ?BL,A
LDW   X,#?LAB_0003
LDW   ?CH,X
POPW  X
INCW  X
LDF   A,([?BL.e],X)
PUSH  A
DECW  X
LDF   A,([?BL.e],X)
PUSH  A
POPW  X
JP    X,(X)

Regards,

Stéphane