微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

GNU libc.so是如何共享对象和独立的可执行文件?

在Linux中,GNU标准C库(libc.so)的共享库不仅是一个共享库,还可以作为独立的可执行文件运行,打印出版本信息:

[me@computer ~]$ /lib/libc.so.6 GNU C Library stable release version 2.12,by Roland McGrath et al. copyright (C) 2010 Free Software Foundation,Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or fitness FOR A PARTIculaR PURPOSE. Compiled by GNU CC version 4.4.7 20120313 (Red Hat 4.4.7-11). Compiled on a Linux 2.6.32 system on 2015-01-07. Available extensions: The C stubs add-on version 2.1.2. crypt add-on version 2.1 by Michael Glad and others GNU Libidn by Simon Josefsson Native POSIX Threads Library by Ulrich Drepper et al BIND-8.2.3-T5B RT using linux kernel aio libc ABIs: UNIQUE IFUNC For bug reporting instructions,please see: <http://www.gnu.org/software/libc/bugs.html>.

他们是怎么做到的? 我试图创build一个共享库,也碰巧有一个main()函数,但它试图运行它segfaulted。

我试过的:

/* myso.c */ #include <stdlib.h> #include <stdio.h> static void foo(void) { printf("hello foon"); } int main(int argc,char *argv[]) { printf("hello worldn"); foo(); return 0; }

然后:

你可以编译一个共享对象来使用本地符号,即使它正在用-rdynamic编译的程序加载吗?

dlsym()在C ++中的全局variables

识别哪个Linux系统库包含一个函数

共享库path作为可执行目录

用于从现有文件创build(.so文件的makefile

$ gcc -Wall -fPIC -shared -o myso.so myso.c $ ./myso.so Segmentation fault (core dumped)

作为一个说明:我真的不想为了任何真正的目的而这样做,我只想知道GNU的人(和gals)是如何做到的。

运行ltrace时没有输出

共享库:Windows vs Linux方法

在运行时加载Linux库

了解使用gcc的共享库

什么是关于Linux上的共享库的良好做法?

在glibc文件Makerules中:

# Give libc.so an entry point and make it directly runnable itself. LDFLAGS-c.so += -e __libc_main

并在csu/version.c

extern void __libc_print_version (void); void __libc_print_version (void) { __write (STDOUT_FILENO,banner,sizeof banner - 1); }

这由__libc_main()调用

文件elf/interp.c ,程序解释器被添加到共享对象。

这在64位Linux上适用于我: gcc -Wall -Wextra -fPIC -shared -o myso.so myso.c

//myso.c #include <unistd.h> char const __invoke_dynamic_linker__[] __attribute__ ((section (".interp"))) #ifdef __LP64__ = "/lib64/ld-linux-x86-64.so.2"; #else = "/lib/ld-linux.so.2"; #endif void _start(void) { static char const msg[] = "Hello World!n"; write(STDOUT_FILENO,msg,sizeof msg - 1); _exit(0); }

__invoke_dynamic_linker__[]行是需要的,因为没有它动态链接write和_exit不能完成。 这个变量的名字并不重要。 有一个选项ld , -dynamic-linker ,它可以做同样的事情,但是用-shared忽略,但是把代码放到源代码中就行了。

这是一个没有动态链接的变体:

#include <unistd.h> #include <sys/syscall.h> __asm__( #ifdef __LP64__ "syscall: mov %rdi,%rax;" " mov %rsi,%rdi;" " mov %rdx,%rsi;" " mov %rcx,%rdx;" " mov %r8,%r10;" " mov %r9,%r8;" " mov 0x8(%rsp),%r9;" " syscall;" " cmp $0xfffffffffffff001,%rax;" " jae __syscall_error;" " retq; " "__syscall_error: neg %rax;" " mov %eax,%fs:0xffffffffffffffd0;" " or $0xffffffffffffffff,%rax;" " retq;" #else "syscall: push %ebp;" " push %edi;" " push %esi;" " push %ebx;" " mov 0x2c(%esp),%ebp;" " mov 0x28(%esp),%edi;" " mov 0x24(%esp),%esi;" " mov 0x20(%esp),%edx;" " mov 0x1c(%esp),%ecx;" " mov 0x18(%esp),%ebx;" " mov 0x14(%esp),%eax;" " int $0x80;" " pop %ebx;" " pop %esi;" " pop %edi;" " pop %ebp;" " cmp $0xfffff001,%eax;" " jae __syscall_error;" " ret;" "__syscall_error: neg %eax;" " mov %gs:0x0,%ecx;" " mov %eax,-0x18(%ecx);" " mov $0xffffffff,%eax;" " ret;" #endif ); void _start(void) { static char const msg[] = "Hello World!n"; syscall(SYS_write,STDOUT_FILENO,sizeof msg - 1); syscall(SYS_exit,0); }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐