When a varags function (like printf) is passed a non-generic pointer (__code char *, for instance), that argument is not promoted to a generic pointer when pushed on the stack. This is a change from the 2.8 version which did this promotion.
The test is small enough to include in-line here:
extern void f(char *x, ...);
void
func(__code char *s)
{
f("hi", s);
}
SDCC command:
$ sdcc -c --model-small --debug --opt-code-speed -otest.rel test.c
SDCC version:
SDCC : mcs51/gbz80/z80/avr/ds390/pic16/pic14/TININative/xa51/ds400/hc08 2.9.0 #5416 (Apr 9 2009) (UNIX)
Incorrect output (note missing mov a,#0x80; push acc after the push ar3)
0000 AA 82 109 mov r2,dpl
0002 AB 83 110 mov r3,dph
0004 111 C$test.c$6$1$1 ==.
112 ; test.c:6: f("hi", s);
0004 C0 02 113 push ar2
0006 C0 03 114 push ar3
0008 74r00 115 mov a,#__str_0
000A C0 E0 116 push acc
000C 74s00 117 mov a,#(__str_0 >> 8)
000E C0 E0 118 push acc
0010 74 80 119 mov a,#0x80
0012 C0 E0 120 push acc
0014 12s00r00 121 lcall _f
Email address: keithp@keithp.com
Patch to pass RESULT_TYPE_GPTR for varargs pointers
On 28 Dec 2008, Maarten Brock added RESULT_TYPE_GPTR as a distinct case from RESULT_TYPE_NONE, but it looks like that didn't include changes to make the varargs parameter passing code use RESULT_TYPE_GPTR in cases that involved passing pointers. I've attached a patch which passes RESULT_TYPE_GPTR for the two pointer cases in the varargs parameter type computation.
I already had the feeling it had to do with this change of mine. But I'm still uncertain if I should consider this a bug or a feature. Sending only as many bytes as required seems a good idea. I'm sure that if you add an explicit cast to a generic pointer it will send a generic pointer. And only the recipient knows what to expect, in this case probably a generic pointer due to using "%p" as the formatter. And printf does not (yet) support "%cp" for code pointers, "%xp" for xdata pointers, etc.
I would like to hear other peoples opinion on this case. Should SDCC always send a generic pointer as argument to a function with a variable number of arguments? Or just send whatever you give to it?
I think this case should be handled similar to passing 8-bit char's as int arguments to printf(). Do we promote them to int or are they passed as given?
In sdccman, section 1.4 Compatibility with previous versions, is written:
"char type parameters to vararg functions are casted to int unless explicitly casted and --std-c89 and --std-c99 command line option are not defined , e.g.:
char a=3;
printf ("%d %c\n", a, (char)a);
will push a as an int and as a char resp if --std-c89 and --std-c99 command line options are not defined, will push a as two ints if --std-c89 or --std-c99 command line option is defined."
See also https://sourceforge.net/tracker/?func=detail&aid=1874922&group_id=599&atid=100599
For the pointers I'm more favorable to generic pointer passing in case of varargs.
We could use --std-cXX approach too: pass generic pointer if --std-cXX is defined and pass the pointer type defined by caller if --std-cXX is not defined.
Borut
I can't figure out how I'd pass a generic pointer with 2.9.0; adding an explicit cast to (char *) generates precisely the same code as without the cast; it's the cast type conversion code which is broken precisely in this case, after all (ask for RESULT_TYPE_NONE and you'll never get a generic pointer).
With 2.8.0 (or 2.9.0 with my patch), you can ask the code to pass a short pointer with an explicit cast to __xdata (or whatever). Without my patch, you can't ever get a generic pointer.
Keith,
If casting does not help then this definitely is a bug.
And since others prefer to send generic pointers by default, that's how it will be.
Only with an explicit cast it will be transferred as a non-generic pointer.
I'll have a look at the patch.
Fixed in SDCC 2.9.1 #5445.
Applied the patch without changes, thanks.
Maarten,
I think that behavior of passing pointers as varargs should be also documented in sdccman.lyx.
Borut
It took me some time to get a recent version of LyX setup, but now the behaviour is documented as well.