Build executable with ld

1 篇文章 0 订阅

如何编译动态可执行文件

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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值