Floating-point variadic function call

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Floating-point variadic function call

Damien Thébault
Hello,

I am trying to use libffi to call various functions, and my first try
was with printf(). As this is a variadic function, I used
ffi_prep_cif_var(). Everything seems to be working, except with floats,
which are not working, and are even generating wrong memory accesses
(detected by valgrind).

A similar function with ffi_prep_cif() and floats is working properly.

Could type promotion from float to double be the issue here ?
Does libffi handle type promotion in variadic calls or is it the
caller's job ?

I tested on a x86_64 computer both 64-bit and 32-bit versions (the
latter compiled with -m32) as well as ARM under qemu.
In all those cases, I didn't get the proper result with floats while
doubles are ok, as well as chars.
I've attached a sample source file that reproduces the problem and here
is the output of one test run:

 $ gcc $(pkg-config --cflags --libs libffi) -std=c99 -pedantic -Wall -Wextra libffi_variadic_printf.c -o libffi_variadic_printf
 $ ./libffi_variadic_printf
Non-variadic call:
[1.100000,2.200000,3.300000,4.400000,5.500000,6.600000,7.700000,8.800000,9.900000]
result is 83
Variadic call:
[0.000000,0.000000,0.000000,0.000000,0.000000,91750.390826,0.000000,0.000000,0.000000]
result is 87

Thanks,

libffi_variadic_printf.c (2K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Floating-point variadic function call

Andrew Pinski-6
On Mon, Oct 10, 2016 at 12:03 AM, Damien Thébault <[hidden email]> wrote:

> Hello,
>
> I am trying to use libffi to call various functions, and my first try
> was with printf(). As this is a variadic function, I used
> ffi_prep_cif_var(). Everything seems to be working, except with floats,
> which are not working, and are even generating wrong memory accesses
> (detected by valgrind).
>
> A similar function with ffi_prep_cif() and floats is working properly.
>
> Could type promotion from float to double be the issue here ?
> Does libffi handle type promotion in variadic calls or is it the
> caller's job ?
>
> I tested on a x86_64 computer both 64-bit and 32-bit versions (the
> latter compiled with -m32) as well as ARM under qemu.
> In all those cases, I didn't get the proper result with floats while
> doubles are ok, as well as chars.

That is because the variadic function ABI is different from the normal
argument ABI on ARM hard-float EABI.  Basically for variadic functions
float are passed via the integer registers while for normal functions,
they are passed via the vfp registers.

Basically you need to use variadic function support in libff.  Use
ffi_prep_cif_var instead of ffi_prep_cif and then don't do:

    for(i=1 ; i<10 ; i++)
    {
        arg_types[i] = &ffi_type_float;
    }


Thanks,
Andrew Pinski

> I've attached a sample source file that reproduces the problem and here
> is the output of one test run:
>
>  $ gcc $(pkg-config --cflags --libs libffi) -std=c99 -pedantic -Wall -Wextra libffi_variadic_printf.c -o libffi_variadic_printf
>  $ ./libffi_variadic_printf
> Non-variadic call:
> [1.100000,2.200000,3.300000,4.400000,5.500000,6.600000,7.700000,8.800000,9.900000]
> result is 83
> Variadic call:
> [0.000000,0.000000,0.000000,0.000000,0.000000,91750.390826,0.000000,0.000000,0.000000]
> result is 87
>
> Thanks,
Reply | Threaded
Open this post in threaded view
|

Re: Floating-point variadic function call

Damien Thébault
On Mon, Oct 10, 2016 at 12:17:03AM -0700, Andrew Pinski wrote:

> > I tested on a x86_64 computer both 64-bit and 32-bit versions (the
> > latter compiled with -m32) as well as ARM under qemu.
> > In all those cases, I didn't get the proper result with floats while
> > doubles are ok, as well as chars.
>
> That is because the variadic function ABI is different from the normal
> argument ABI on ARM hard-float EABI.  Basically for variadic functions
> float are passed via the integer registers while for normal functions,
> they are passed via the vfp registers.
>
> Basically you need to use variadic function support in libff.  Use
> ffi_prep_cif_var instead of ffi_prep_cif and then don't do:
>
>     for(i=1 ; i<10 ; i++)
>     {
>         arg_types[i] = &ffi_type_float;
>     }

I'm actually using ffi_prep_cif_var() for the variadic call, but what
should I put as arg_type then ?

Thanks,
--
Damien Thébault
Reply | Threaded
Open this post in threaded view
|

Re: Floating-point variadic function call

Richard Henderson-2
On 10/10/2016 02:27 AM, Damien Thébault wrote:

> On Mon, Oct 10, 2016 at 12:17:03AM -0700, Andrew Pinski wrote:
>>> I tested on a x86_64 computer both 64-bit and 32-bit versions (the
>>> latter compiled with -m32) as well as ARM under qemu.
>>> In all those cases, I didn't get the proper result with floats while
>>> doubles are ok, as well as chars.
>>
>> That is because the variadic function ABI is different from the normal
>> argument ABI on ARM hard-float EABI.  Basically for variadic functions
>> float are passed via the integer registers while for normal functions,
>> they are passed via the vfp registers.
>>
>> Basically you need to use variadic function support in libff.  Use
>> ffi_prep_cif_var instead of ffi_prep_cif and then don't do:
>>
>>     for(i=1 ; i<10 ; i++)
>>     {
>>         arg_types[i] = &ffi_type_float;
>>     }
>
> I'm actually using ffi_prep_cif_var() for the variadic call, but what
> should I put as arg_type then ?

You must do the mandatory C promotion yourself.  Put ffi_type_double.


r~

Reply | Threaded
Open this post in threaded view
|

Re: Floating-point variadic function call

Damien Thébault
On Tue, 11 Oct 2016 08:27:02 -0500
Richard Henderson <[hidden email]> wrote:
> > I'm actually using ffi_prep_cif_var() for the variadic call, but
> > what should I put as arg_type then ?  
>
> You must do the mandatory C promotion yourself.  Put ffi_type_double.

Ok thank you, I will handle that on my side then, this should not be a
problem.

--
Damien Thébault