public inbox for libffi-discuss@sourceware.org
 help / color / mirror / Atom feed
* Floating-point variadic function call
@ 2016-10-10  7:04 Damien Thébault
  2016-10-10  7:17 ` Andrew Pinski
  0 siblings, 1 reply; 5+ messages in thread
From: Damien Thébault @ 2016-10-10  7:04 UTC (permalink / raw)
  To: libffi-discuss

[-- Attachment #1: Type: text/plain, Size: 1240 bytes --]

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,

[-- Attachment #2: libffi_variadic_printf.c --]
[-- Type: text/x-c, Size: 2018 bytes --]


#include <stdio.h>
#include <ffi.h>

int print9float(const char *fmt,
                float f1, float f2, float f3, float f4, float f5,
                float f6, float f7, float f8, float f9)
{
    return printf(fmt, f1, f2, f3, f4, f5, f6, f7, f8, f9);
}

void test_float()
{
    size_t i;
    ffi_cif cif;
    ffi_type *arg_types[10];
    void     *arg_values[10];
    char *fmt = "[%f,%f,%f,%f,%f,%f,%f,%f,%f]\n";
    float floatargs[9] = {1.1f,2.2f,3.3f,4.4f,5.5f,6.6f,7.7f,8.8f,9.9f};
    ffi_status status;
    int result;
    arg_types[0] = &ffi_type_pointer;
    for(i=1 ; i<10 ; i++)
    {
        arg_types[i] = &ffi_type_float;
    }
    if((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 10,
                              &ffi_type_sint, arg_types)) != FFI_OK)
    {
        fprintf(stderr, "ffi_prep_cif_var() failed!\n");
        return;
    }
    arg_values[0] = &fmt;
    for(i=1 ; i<10 ; i++)
    {
        arg_values[i] = &floatargs[i-1];
    }
    printf("Non-variadic call:\n");
    ffi_call(&cif, FFI_FN(print9float), &result, arg_values);
    printf("result is %i\n", result);
}

void test_varfloat()
{
    size_t i;
    ffi_cif cif;
    ffi_type *arg_types[10];
    void     *arg_values[10];
    char *fmt = "[%f,%f,%f,%f,%f,%f,%f,%f,%f]\n";
    float floatargs[9] = {1.1f,2.2f,3.3f,4.4f,5.5f,6.6f,7.7f,8.8f,9.9f};
    ffi_status status;
    int result;
    arg_types[0] = &ffi_type_pointer;
    for(i=1 ; i<10 ; i++)
    {
        arg_types[i] = &ffi_type_float;
    }
    if((status = ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 10,
                                  &ffi_type_sint, arg_types)) != FFI_OK)
    {
        fprintf(stderr, "ffi_prep_cif_var() failed!\n");
        return;
    }
    arg_values[0] = &fmt;
    for(i=1 ; i<10 ; i++)
    {
        arg_values[i] = &floatargs[i-1];
    }
    printf("Variadic call:\n");
    ffi_call(&cif, FFI_FN(printf), &result, arg_values);
    printf("result is %i\n", result);
}

int main()
{
    test_float();
    test_varfloat();
    return 0;
}


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Floating-point variadic function call
  2016-10-10  7:04 Floating-point variadic function call Damien Thébault
@ 2016-10-10  7:17 ` Andrew Pinski
  2016-10-10  7:27   ` Damien Thébault
  0 siblings, 1 reply; 5+ messages in thread
From: Andrew Pinski @ 2016-10-10  7:17 UTC (permalink / raw)
  To: Damien Thébault; +Cc: libffi-discuss

On Mon, Oct 10, 2016 at 12:03 AM, Damien Thébault <damien@dtbo.net> 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,

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Floating-point variadic function call
  2016-10-10  7:17 ` Andrew Pinski
@ 2016-10-10  7:27   ` Damien Thébault
  2016-10-11 13:27     ` Richard Henderson
  0 siblings, 1 reply; 5+ messages in thread
From: Damien Thébault @ 2016-10-10  7:27 UTC (permalink / raw)
  To: Andrew Pinski; +Cc: libffi-discuss

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

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Floating-point variadic function call
  2016-10-10  7:27   ` Damien Thébault
@ 2016-10-11 13:27     ` Richard Henderson
  2016-10-11 19:12       ` Damien Thébault
  0 siblings, 1 reply; 5+ messages in thread
From: Richard Henderson @ 2016-10-11 13:27 UTC (permalink / raw)
  To: Damien Thébault, Andrew Pinski; +Cc: libffi-discuss

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~

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Floating-point variadic function call
  2016-10-11 13:27     ` Richard Henderson
@ 2016-10-11 19:12       ` Damien Thébault
  0 siblings, 0 replies; 5+ messages in thread
From: Damien Thébault @ 2016-10-11 19:12 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Andrew Pinski, libffi-discuss

On Tue, 11 Oct 2016 08:27:02 -0500
Richard Henderson <rth@redhat.com> 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

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-10-11 19:12 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-10  7:04 Floating-point variadic function call Damien Thébault
2016-10-10  7:17 ` Andrew Pinski
2016-10-10  7:27   ` Damien Thébault
2016-10-11 13:27     ` Richard Henderson
2016-10-11 19:12       ` Damien Thébault

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).