Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to printf floating point numbers from executable shared library

I'm developing a shared library which can be executed independently to print it's own version number.

I've defined a custom entry point as:

const char my_interp[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";

void my_main() {
   printf("VERSION: %d\n", 0);
   _exit(0);
}

and I compile with

gcc -o list.os -c -g -Wall -fPIC list.c
gcc -o liblist.so -g -Wl,-e,my_main -shared list.os -lc

This code compiles and runs perfectly.

My issue is when I change the parameter of the printf to be a float or double (%f or %lf). The library will then compile but segfault when run.

Anyone have any ideas?

edit1:

Here is the code that segfaults:

const char my_interp[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2"; 

void my_main() { 
    printf("VERSION: %f\n", 0.1f); 
    _exit(0); 
} 

edit2:

Additional environmental details:

uname -a

Linux mjolnir.site 3.1.10-1.16-desktop #1 SMP PREEMPT Wed Jun 27 05:21:40 UTC 2012 (d016078) x86_64 x86_64 x86_64 GNU/Linux

gcc --version

gcc (SUSE Linux) 4.6.2

/lib64/libc.so.6

Configured for x86_64-suse-linux. Compiled by GNU CC version 4.6.2. Compiled on a Linux 3.1.0 system on 2012-03-30.

edit 3:

Output in /var/log/messages upon segfault:

Aug 11 08:27:45 mjolnir kernel: [10560.068741] liblist.so[11222] general protection ip:7fc2b3cb2314 sp:7fff4f5c7de8 error:0 in libc-2.14.1.so[7fc2b3c63000+187000]

like image 429
kobrien Avatar asked Aug 11 '12 06:08

kobrien


1 Answers

Figured it out. :)

The floating point operations on x86_64 use the xmm vector registers. Access to these must be aligned on 16byte boundaries. This explains why 32bit platforms were unaffected and integer and character printing worked.

I've compiled my code to assembly with:

gcc -W list.c -o list.S -shared -Wl,-e,my_main -S -fPIC

then altered the "my_main" function to be have more stack space.

Before:

my_main:
 .LFB6:
 .cfi_startproc
 pushq   %rbp
 .cfi_def_cfa_offset 16
 .cfi_offset 6, -16
 movq    %rsp, %rbp
 .cfi_def_cfa_register 6
 movl    $.LC0, %eax
 movsd   .LC1(%rip), %xmm0
 movq    %rax, %rdi
 movl    $1, %eax
 call    printf
 movl    $0, %edi
 call    _exit
 .cfi_endproc

After:

my_main:
 .LFB6:
 .cfi_startproc
 pushq   %rbp
 .cfi_def_cfa_offset 16
 .cfi_offset 6, -16
 subq    $8, %rsp ;;;;;;;;;;;;;;; ADDED THIS LINE
 movq    %rsp, %rbp
 .cfi_def_cfa_register 6
 movl    $.LC0, %eax
 movsd   .LC1(%rip), %xmm0
 movq    %rax, %rdi
 movl    $1, %eax
 call    printf
 movl    $0, %edi
 call    _exit
 .cfi_endproc

Then I compiled this .S file by:

gcc list.S -o liblist.so -Wl,-e,my_main -shared

This fixes the issue, but I will forward this thread to the GCC and GLIBC mailing lists, as it looks like a bug.

edit1:

According to noshadow in gcc irc, this is a non standard way to do this. He said if one is to use gcc -e option, either initialize the C runtime manually, or don't use libc functions. Makes sense.

like image 67
kobrien Avatar answered Oct 08 '22 00:10

kobrien