Не удалось напечатать числа с плавающей запятой из исполняемой разделяемой библиотеки

Я разрабатываю общую библиотеку, которая может быть выполнена независимо, чтобы напечатать собственный номер версии.

Я определил пользовательскую точку входа как:

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

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

и скомпилировать с помощью

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

Этот код компилирует и работает отлично.

Моя проблема в том, что я изменяю параметр printf как float или double (% f или% lf). Затем библиотека будет компилироваться, но segfault при запуске.

У кого-нибудь есть идеи?

edit1:

Вот код, который 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:

Дополнительные экологические детали:

uname -a

Linux mjolnir.site 3.1.10-1.16-desktop # 1 SMP PREEMPT Ср июн 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

Конфигурируется для x86_64-suse-linux. Составлено GNU CC версии 4.6.2. Скомпилирован в Linux 3.1.0 в 2012-03-30.

изменить 3:

Вывод в/var/log/сообщения по segfault:

11 августа 08:27:45 mjolnir kernel: [10560.068741] liblist.so [11222] общая защита ip: 7fc2b3cb2314 sp: 7fff4f5c7de8 error: 0 в libc-2.14.1.so [7fc2b3c63000 + 187000]

Ответ 1

Выяснил это.:)

Операции с плавающей запятой на x86_64 используют векторные регистры xmm. Доступ к ним должен быть выровнен по границам 16 байт. Это объясняет, почему 32-битные платформы не подвергались воздействию, а работа с целыми и печатными символами работала.

Я скомпилировал свой код для сборки с помощью:

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

затем изменил функцию "my_main", чтобы иметь больше пространства стека.

До:

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

После того, как:

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

Затем я скомпилировал этот файл .S:

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

Это исправляет проблему, но я перенаправляю этот поток в списки рассылки GCC и GLIBC, поскольку это похоже на ошибку.

edit1:

В соответствии с noshadow в gcc irc это нестандартный способ сделать это. Он сказал, что если нужно использовать опцию gcc -e, либо инициализировать C runtime вручную, либо не использовать функции libc. Имеет смысл.