Calling a function with float parameter on a dynamic library cannot get the correct value

I designed a function with float parameter on the dynamic library(.so). But the function cannot get the correct value that I passed.

Code sample 1

mylib.c

void pass_float_to_lib(float a_float)
{
    printf("Lib get %f\n", a_float);
}

main.c

int main(void)
{
    float my_float = 1.3;
    printf("Pass %f\n", my_float);
    pass_float_to_lib(my_float);
    return 0;
}

output:

Pass 1.300000

Lib get -2.000000

Why I pass float 1.3 to the library but it gets -2.000000

Therefore, I pass float value to another function beside main.c, and Add some debug message. I found that the float value between the stacks (between char guard_a and gyard_b) is not what I passed.

Code sample 2

main.c:

void pass_float(char guard_a, float a_float, char guard_b)
{
    printf("The float is %f\n", a_float);
    printf("address:\n"
        "grard_a %p\n"
        "a_float %p\n"
        "guard_b %p\n",
        &guard_a, &a_float, &guard_b);

    char *p_stack = &guard_b;
    while (p_stack <= &guard_a) {
        printf("Addr %p: Byte %x \n", p_stack, *p_stack & 0xff);
        p_stack++;
    }
}

int main(void)
{
    float my_float = 1.3;
    printf("Test A\n");
    pass_float('a', my_float, 'b');
    pass_float_to_lib('a', my_float, 'b');

    printf("Test B\n");
    char *p = (char *) &my_float;
    *p++ = 0x11;
    *p++ = 0x22;
    *p++ = 0x33;
    *p++ = 0x44;
    pass_float('a', my_float, 'b');
    pass_float_to_lib('a', my_float, 'b');

    return 0;
}

mylib.c

void pass_float_to_lib(char guard_a, float a_float, char guard_b)
{

    printf("The float is %f\n", a_float);
    printf("address:\n"
        "grard_a %p\n"
        "a_float %p\n"
        "guard_b %p\n",
        &guard_a, &a_float, &guard_b);

    char *p_stack = &guard_b;
    while (p_stack <= &guard_a) {
        printf("Addr %p: Byte %x \n", p_stack, *p_stack & 0xff);
        p_stack++;
    }
}

output:

Test A
The float is 1.300000
address:
grard_a 0x7ffc72d987ec
a_float 0x7ffc72d987e8
guard_b 0x7ffc72d987e4
Addr 0x7ffc72d987e4: Byte 62
Addr 0x7ffc72d987e5: Byte 0
Addr 0x7ffc72d987e6: Byte 0
Addr 0x7ffc72d987e7: Byte 0
Addr 0x7ffc72d987e8: Byte 66
Addr 0x7ffc72d987e9: Byte 66
Addr 0x7ffc72d987ea: Byte a6
Addr 0x7ffc72d987eb: Byte 3f
Addr 0x7ffc72d987ec: Byte 61

The float is -2.000000
address:
grard_a 0x7ffc72d987ec
a_float 0x7ffc72d987e8
guard_b 0x7ffc72d987e4
Addr 0x7ffc72d987e4: Byte 62
Addr 0x7ffc72d987e5: Byte 0
Addr 0x7ffc72d987e6: Byte 0
Addr 0x7ffc72d987e7: Byte 0
Addr 0x7ffc72d987e8: Byte 0
Addr 0x7ffc72d987e9: Byte 0
Addr 0x7ffc72d987ea: Byte 0
Addr 0x7ffc72d987eb: Byte c0
Addr 0x7ffc72d987ec: Byte 61

Test B
The float is 716.532288
address:
grard_a 0x7ffc72d987ec
a_float 0x7ffc72d987e8
guard_b 0x7ffc72d987e4
Addr 0x7ffc72d987e4: Byte 62
Addr 0x7ffc72d987e5: Byte 0
Addr 0x7ffc72d987e6: Byte 0
Addr 0x7ffc72d987e7: Byte 0
Addr 0x7ffc72d987e8: Byte 11
Addr 0x7ffc72d987e9: Byte 22
Addr 0x7ffc72d987ea: Byte 33
Addr 0x7ffc72d987eb: Byte 44
Addr 0x7ffc72d987ec: Byte 61

The float is 0.000000
address:
grard_a 0x7ffc72d987ec
a_float 0x7ffc72d987e8
guard_b 0x7ffc72d987e4
Addr 0x7ffc72d987e4: Byte 62
Addr 0x7ffc72d987e5: Byte 0
Addr 0x7ffc72d987e6: Byte 0
Addr 0x7ffc72d987e7: Byte 0
Addr 0x7ffc72d987e8: Byte 0
Addr 0x7ffc72d987e9: Byte 0
Addr 0x7ffc72d987ea: Byte 0
Addr 0x7ffc72d987eb: Byte 20
Addr 0x7ffc72d987ec: Byte 61

The following commands are the steps to compile the code.

Compile dynamic library:

  • gcc -fPIC -O -c mylib.c -o mylib.o

  • gcc -shared mylib.o -o libmylib.so

Compile main and execute it:

  • gcc -O -c main.c
  • gcc main.o -L. -lmylib
  • LD_LIBRARY_PATH=. ./a.out

>Solution :

Declare the routine before you call it. Without a declaration, the compiler treats the function as implicitly declared, the default argument promotions are performed, and the float is converted to a double. This results in the data being passed and interpreted incorrectly.

Taking the addresses of the parameters and printing the memory there is useless. Arguments are commonly passed in registers. Then, when you take the address of a parameter, the compiler copies it to memory solely for the purpose of having an address. The addresses the compiler uses for this for various parameters does not necessarily have any relationship to how those parameters appear in the registers.

Leave a Reply