2012-08-11 105 views
10

我正在开发一个可以独立执行的共享库来打印它自己的版本号。无法从可执行共享库中打印浮点数

我已经定义了一个自定义的入口点为:

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)时。然后该库将在运行时编译但段错误

任何人有任何想法?

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-桌面#1 SMP PREEMPT星期三06月27五点21分四十秒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编译。 在2012年3月30日的Linux 3.1.0系统上编译。

年08月11八点27分45秒MJOLNIR内核::[10560.068741] liblist.so [11222]一般

编辑3:在段错误

输出在/ var /日志/消息保护ip:7fc2b3cb2314 sp:7fff4f5c7de8错误:0在libc-2.14.1.so [7fc2b3c63000 + 187000]

+1

这对我的32位机器来说是完美的。它也应该在64位上工作。你包括? – TOC 2012-08-11 06:40:55

+1

@TOC我做到了。您是否尝试打印浮点数作为版本号?我发布的代码工作正常,除了打印浮动。 – kobrien 2012-08-11 06:43:25

+0

你可以显示打印浮球的代码吗? – 2012-08-11 06:43:48

回答

5

找出来了。 :)

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运行时,或者不要使用libc函数。说得通。

+0

ISTR有一个选项让gcc在比默认边界更大的边界上对齐堆栈。您可以使用它作为解决方案,直到错误修复而不是修改程序集。 – AProgrammer 2012-08-11 11:08:42

+0

听起来不错。另一种方法是不使用libc函数并直接使用系统调用,但请注意,这是更多的代码和更少的可移植性。 – kobrien 2012-08-11 11:26:45

+1

将单个浮点值加载到XMM寄存器的指令不需要16字节对齐。对于双精度,它们只需要四个字节的对齐用于单精度和八字节对齐。您可能遇到过其他问题,例如违反了应用程序二进制接口调用子例程的要求(可能会错误地对齐堆栈,可能未能设置指示浮点参数通过的位或其他问题)。 – 2012-08-11 18:21:05