如何编译动态可执行文件
1. 实例代码如下
#include <stdio.h>
#include <string.h>
#include <unistd.h>
const char elf_interpreter[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";
const char *name = "hello world\n";
int a;
static void init(void) __attribute__((constructor));
static void finish(void) __attribute__((destructor));
int main() {
a = 100;
printf("a %p, val %d, str %p, len %d\n", &a, a, name, strlen(name));
_exit(0);
}
static void init() {
printf("hi init\n");
}
static void finish() {
printf("hi finished\n");
}
编译命令:
gcc -g -shared -fPIC -o libhellox.so hello-so.c -lc -Wl,-emain
./libhellox.so
a 0x7f087d95ebc0, val 100, str 0x7f087d75e876, len 12
查看elf文件头信息:
readelf -h libhellox.so
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x79c
Start of program headers: 64 (bytes into file)
Start of section headers: 4312 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 8
Size of section headers: 64 (bytes)
Number of section headers: 37
Section header string table index: 34
1. 动态可执行程序跟编译动态库的编译选项是一样的, 即都要加
-shared -fPIC
2.这两个选项是用来编译动态库的,要想 使它可以执行必须指定入口, 否则默认第一个函数是入口
-Wl,-emain
3. 因为默认入口是main,这样就跳过了libc的默认_start入口,所以直接return 0是会出错的,需要在最后加_exit(0)
4.因为入口不是_start,libc里面在初始化和退出时做的工作将没有执行,上面代码的init,exit函数都没有执行
5. 动态库默认没有loader,但是可执行程序必须存在,需要添加.interp section并制定loader地址;
const char elf_interpreter[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";
鉴于上述方式编译动态可执行程序存在的问题,gcc提供了一个简单的方式,即PIE
gcc -pie -fPIE -o libhellox.pie hello-so.c
只要在编译是加上-pie -fPIE, 就可以将原来的可执行文件编译成动态可执行文件
$ ./libhellox.pie
hi init
a 0x7f2e6d585d40, val 100, str 0x7f2e6d38599c, len 12
hi finished
$ ./libhellox.pie
hi init
a 0x7f684079fd40, val 100, str 0x7f684059f99c, len 12
hi finished
查看elf文件信息:
readelf -h libhellox.pie
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x720
Start of program headers: 64 (bytes into file)
Start of section headers: 3736 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 8
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 28
gcc tips:
使用-### 选项实现了类似dry run 的功能,即只打印出执行命令,也可以使用-v,在实际编译过程中打印出相关的命令:
gcc -### -pie -fPIE -o libhellox.pie hello-pie.c
Using built-in specs.
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)
COLLECT_GCC_OPTIONS='-pie' '-fPIE' '-o' 'libhellox.pie' '-mtune=generic'
"/usr/libexec/gcc/x86_64-redhat-linux/4.4.6/cc1" "-quiet" "hello-pie.c" "-quiet" "-dumpbase" "hello-pie.c" "-mtune=generic" "-auxbase" "hello-pie" "-fPIE" "-o" "/tmp/ccdbk8Jy.s"
COLLECT_GCC_OPTIONS='-pie' '-fPIE' '-o' 'libhellox.pie' '-mtune=generic'
"as" "-Qy" "-o" "/tmp/cc3P6w7E.o" "/tmp/ccdbk8Jy.s"
COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.4.6/:/usr/libexec/gcc/x86_64-redhat-linux/4.4.6/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.4.6/:/usr/lib/gcc/x86_64-redhat-linux/:/usr/libexec/gcc/x86_64-redhat-linux/4.4.6/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.4.6/:/usr/lib/gcc/x86_64-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.4.6/:/usr/lib/gcc/x86_64-redhat-linux/4.4.6/:/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-pie' '-fPIE' '-o' 'libhellox.pie' '-mtune=generic'
"/usr/libexec/gcc/x86_64-redhat-linux/4.4.6/collect2" "--eh-frame-hdr" "--build-id" "-m" "elf_x86_64" "--hash-style=gnu" "-dynamic-linker" "/lib64/ld-linux-x86-64.so.2" "-pie" "-o" "libhellox.pie" "/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../lib64/Scrt1.o" "/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../lib64/crti.o" "/usr/lib/gcc/x86_64-redhat-linux/4.4.6/crtbeginS.o" "-L/usr/lib/gcc/x86_64-redhat-linux/4.4.6" "-L/usr/lib/gcc/x86_64-redhat-linux/4.4.6" "-L/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../lib64" "-L/lib/../lib64" "-L/usr/lib/../lib64" "-L/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../.." "/tmp/cc3P6w7E.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "/usr/lib/gcc/x86_64-redhat-linux/4.4.6/crtendS.o" "/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../lib64/crtn.o"
参考链接:
http://blog.techveda.org/building-executables-with-gnu-linker/
http://www.tldp.org/LDP/LG/issue83/sandeep.html
http://www.tldp.org/LDP/LG/issue85/sandeep.html
http://dandylife.net/blog/archives/660
http://www.mindfruit.co.uk/2012/06/relocations-relocations.html
https://codywu2010.wordpress.com/2014/11/29/about-elf-pie-pic-and-else/#comment-385
http://amir.rachum.com/blog/2016/09/17/shared-libraries/