The main problem here is how the variable arguments are passed to the function.
Usually, they are passed on the stack, but as far as I know, it's not the case with the ARM ABI, where registers are used, at least when possible.
So you've got two issues here.
First, the compiler may mess up those registers, while executing the code of your own method.
I'm not sure about this, as I don't know much about the ARM ABI, so you should check in the reference.
Second issue, more important, you are actually passing a single variable argument to obj_msgSend
(the va_list
). So the target method won't receive what it expects, obviously.
Imagine the following:
void bar( int x, ... )
{}
void foo( void )
{
bar( 1, 2, 3, 4 );
}
On ARM, this will mean, for the foo
function:
movs r0, #1
movt r0, #0
movs r1, #2
movt r1, #0
movs r2, #3
movt r2, #0
movs r3, #4
movt r3, #0
bl _bar
Variables arguments are passed in R1
, R2
and R3
, and the int
argument in R0
.
So in your case, as a call to objc_msdSend
was used to call your method, R0
should be the target object's pointer, R1
the selector's pointer, and variable arguments should begin on R2
.
And when issuing your own call to objc_msdSend
, you're at least overwriting the content of R2
, with your va_list
.
You should try not to care about the variable arguments. With a little luck, if the code previous to the objc_msgSend
call (where you get the final selector) doesn't mess up those registers, the correct values should still be there, making them available for the target method.
This would of course only work on the real device, and not in the simulator (simulator is x86, so variadic parameters are here passed on the stack).