Original Post

Hi guys, does anyone know if the gccvb compiler supports variadic functions?

I have a function of the form:

// propagate an event to the children wrapper
void Container_propagateEvent(Container this, int (*event)(Container this, va_list args), …){

va_list args;
va_start(args, event);
Container_passEvent(this, event, args);
va_end(args);

// up until here everything is fine

}

// caller
void test(){

int argument = 1;

// everything works fine up until here
Container_propagateEvent(somePointer, someFunctionAddress, argument);

// call to Container_propagateEvent never came back
}

Everything works except that the call never returns (or don’t return to the proper place).

This is the ASM code generated to save the function return point:

0700c048 <__save_r6_r9>:
700c048: 3f 00 mov lp, r1
700c04a: ea 03 mov r10, lp
700c04c: c3 dc 00 00 st.w r6, 0[sp]
700c050: e3 dc 04 00 st.w r7, 4[sp]
700c054: 03 dd 08 00 st.w r8, 8[sp]
700c058: 23 dd 0c 00 st.w r9, 12[sp]
700c05c: 01 18 jmp [r1]

And here is the code to return to the call point
0700c03c <__return_r31>:
700c03c: e3 cf 10 00 ld.w 16[sp],lp
700c040: 63 a4 14 00 addi 20, sp, sp
700c044: 1f 18 jmp [lp]

Can anyone make sense of it for me πŸ˜› ?

jorgeche

  • This topic was modified 14 years, 9 months ago by jorgeche.
10 Replies

After some research I found that it may be the save_r6_r9 code which is wrong, and I found it in the following files:

lib1funcs.asm:

/* Save registers 6 .. 9 on the stack for variable argument functions */
/* Called via: jalr __save_r6_r9,r10 */
__save_r6_r9:
mov ep,r1
mov sp,ep
sst.w r6,0[ep]
sst.w r7,4[ep]
sst.w r8,8[ep]
sst.w r9,12[ep]
mov r1,ep
jmp [r10]

but it isn’t the same code generated by the compiler, which looks like this:

0700beb0 <__save_r6_r9>:
700beb0: 3f 00 mov lp, r1
700beb2: ea 03 mov r10, lp
700beb4: c3 dc 00 00 st.w r6, 0[sp]
700beb8: e3 dc 04 00 st.w r7, 4[sp]
700bebc: 03 dd 08 00 st.w r8, 8[sp]
700bec0: 23 dd 0c 00 st.w r9, 12[sp]
700bec4: 01 18 jmp [r1]

and in v850.md

;; Save r6-r9 for a variable argument function
(define_insn “save_r6_r9”
[(set (mem:SI (reg:SI 3)) (reg:SI 6))
(set (mem:SI (plus:SI (reg:SI 3) (const_int 4))) (reg:SI 7))
(set (mem:SI (plus:SI (reg:SI 3) (const_int 8))) (reg:SI 8))
(set (mem:SI (plus:SI (reg:SI 3) (const_int 12))) (reg:SI 9))
(clobber (reg:SI 10))]
“TARGET_PROLOG_FUNCTION && ! TARGET_LONG_CALLS”
“jarl __save_r6_r9,r10”
[(set_attr “length” “4”)
(set_attr “cc” “clobber”)])

but this is a “GCC Machine Description” which I’m completely clueless about.

jorgeche

I don’t know what you are talking about, just wanted to say that it’s good to see you’re still active, jorge! I was a bit worried after I did not get a response to my last email. πŸ˜‰

Hi Krisse!… yes sorry about that, I’ve been very busy at work with the release of our latest projects, and my personal projects have kept me far from the VB scene too, but the good news is that I’m halfway with the new version of the engine.

About the variadic functions, are functions with the form

SomeType functionName(SomeType firstParameter, …);

the “…” is called ellipsis and is used to allow the function to being called with a variable number of arguments, for example:

functionName(argument1, argument2, argument3, argument4);
functionName(argument1, argument2);

both calls are legal, and it’s a very handy programming technique to achieve things like propagate different kind of events in a parenting system, which is what I’m trying to accomplish.

But I suspect that the way the compiler handles the save stack frame and return from that kind of function is buggy.

jorgeche

I have no idea about the technical details of how it’s handled in gccvb, so I don’t think I’ll be of help… I have wondered whether they were supported though. So if you can get them to work, that’d be great.

One thing you might want to look at is: http://www.vr32.de/modules/newbb/viewtopic.php?topic_id=3391&forum=2 … the only problem is that it’s written in assembly with just a c prototype to make it callable from c, so it probably won’t tell you much except maybe help with how the assembly output _should_ look.

You might also want to try emailing David Tucker… he may know something about how gccvb handles that kinda stuff.

DogP

I’ve partially fixed it, the save stack frame code looks like this:

__save_r6_r9:
mov r31, r1
mov r10, r31
st.w r6,0[sp]
st.w r7,4[sp]
st.w r8,8[sp]
st.w r9,12[sp]
jmp [r1]

and the return code is:

__return_r31:
ld.w 16[sp],r31
addi 20,sp,sp
jmp [r31]

now the problem seems to be that some registers are pushed into the stack, but the stack is not being displaced the necessary amount of bytes, which the return function is assuming to have been displaced (addi 20,sp,sp). Second, return_31 is trying to retrieve the return address from 16[sp], but it was not saved in save_r6_r9.

So I modified the save_r6_r9 to look like this:

__save_r6_r9:
addi -20,sp,sp /* added line */
mov r31, r1
mov r10, r31
st.w r6,0[sp]
st.w r7,4[sp]
st.w r8,8[sp]
st.w r9,12[sp]
st.w r10,16[sp] /* added line */
jmp [r1]

After testing it, everything seems to work fine, except for one last problem:

Every time that there is a jal instruction, the lp register gets the return address, but when entering the variadic function called, there is a new jal instruction to jump to save_r6_r9, and so, the value of lp is lost.
In other normal functions, the compiler always places the following instruction after a jal cal:

mov lp, r10

so the return address is saved in r10 which is then pushed into the stack.

The problem is that the compiler does not place that instruction as the first instruction of a variadic function:

07000ff6 <_container_propagateevent>:
/* here should go the mov lp, r10 instruction */
7000ff6: 00 ac 6e b0 jal 700c064 <__save_r6_r9>
/* now return address (lp value) is lost */

I haven’t figured out where and how the compiler decides to place or not that instruction, so I’m hacking the code right now using the following:

asm(“movhi 1792, r0, r10”);
asm(“movea 11350, r10, r10”);
/* then call my variadic function */
Container_propagateEvent((Container)this->stage, Container_onKeyPressed, pressedKey);

obviously burning the return address into r10 doesn’t make any sense, it’s just there to test that the save_r6_s9 fix really works, so the question is: anyone knows how can I get the current execution address? is there any way to access the PC (Program counter register)?, since I can’t find it’s name for asm nomenclature.

jorgeche

  • This reply was modified 14 years, 9 months ago by jorgeche.

Almost fixed it, the correct __save_r6_r9 looks like this:

__save_r6_r9:
addi -20,sp,sp
mov r31, r1
mov r10, r31
st.w r6,0[sp]
st.w r7,4[sp]
st.w r8,8[sp]
st.w r9,12[sp]
st.w r10,16[sp]
jmp [r1]

To make the compiler generate the “mov lp, r10” intruction was necessary to edit the file v810.md and change the following line:

“jal __save_r6_r9”
to
“mov r31,r10\;jal __save_r6_r9”

This way the return address is properly saved and retrieved.

One last problem, depending on the number of arguments passed to the function, the compiler moves up the stack pointer, but after returning from the variadic function it doesn’t move down the stack pointer by the same amount:

07002aaa <_level_onkeypressed>:
7002aaa: 63 a4 d0 ff addi -48, sp, sp
7002aae: e3 df 2c 00 st.w lp, 44[sp]
7002ab2: 27 01 mov r7, r9
.
.
.
/* variadic function call next */
7002ade: ff af 2c e5 jal 700100a <_container_propagateevent>

/* notice that the stack should be moved down by 48, not 28 */
7002ae6: 63 a4 1c 00 addi 28, sp, sp
7002aea: 00 a8 0e 94 jr 700bef8 <__return_r31>

The quick solution is to place the instruction:
asm(“addi 20, sp, sp”);

inmediately after the variadic function call but it’s a burden to remember to do so everytime. I’m not sure if I’m capable to track this bug since it appears to go way beyond the variadic function problem into more generic compiler parsing code.

PD: attached are the fixed files which go in gcc-2.95.2\gcc\config\v810

PD2: the v810.md appears to be very sensible to modification, if the one attached gives you problems when compiling, you will have to edit it manually using a *NIX editor (donΒ΄t edit with Windows applications).

jorgeche

  • This reply was modified 14 years, 9 months ago by jorgeche.
  • This reply was modified 14 years, 9 months ago by jorgeche.

I can’t get this to work πŸ™

I’m trying to make an improved version of vbTextOut() that takes a variable amount of parameters (like printf() with its format string, using %d, %s etc.).

I’m basically just making it a wrapper around dasi’s posprintf port (which in itself works great, btw πŸ˜‰ )

#include "posprintf.h"
#include 

void vbTextOut(u16 bgmap, u16 col, u16 row, char *t_string, ...)
/* The font must reside in Character segment 3 */
{
  u16 i = 0;
  u16 pos = row * 64 + col;
  char buf[49]; //(One line on screen is max 48 tiles + terminating null)

  va_list args;
  va_start(args, t_string);

  posprintf(buf, t_string, args);

  va_end(args);

  while(buf[i])
  {
    BGMM[(0x1000 * bgmap) + pos + i] = (u16)buf[i] + 0x600;
    i++;
  }
}

It complies, but just gives me a black screen…

I just switched to using the latest precompiled gccVB from 3/31/2010 by dasi, are the patches from this thread included in it?

No, but I don’t think your code would work anyway; [font=Courier]posprintf[/font] takes a variable list of arguments, not a [font=Courier]va_list[/font].

Hmm… I see. Nevermind then πŸ˜›

  • This reply was modified 13 years, 8 months ago by DanB.
  • This reply was modified 13 years, 8 months ago by DanB.
  • This reply was modified 13 years, 8 months ago by DanB.

A workaround for this bug is to compile with -mno-prolog-function.

 

Write a reply

You must be logged in to reply to this topic.