Linker Options

Table of Contents

1. Linker Options

1.1. init

默认情况下 linker 把发现 _init 函数并把它设置 .dynamic section 中的 DT_INIT

#include <stdio.h>

void _init() {
    printf("%s\n", "init");
}

int main(int argc, char *argv[]) {
    printf("main: %p\n", &main);
    return 0;
}

$> arm-linux-androideabi-gcc test.c -fPIE -pie -O3 -g3
00000474 <_init>:
 474:	e59f0004 	ldr	r0, [pc, #4]	; 480 <_init+0xc>
 478:	e08f0000 	add	r0, pc, r0
 47c:	eaffffc2 	b	38c <puts@plt>
 480:	00000010 	andeq	r0, r0, r0, lsl r0


Dynamic section at offset 0xec0 contains 29 entries:
  Tag        Type                         Name/Value
 ...
 0x0000000c (INIT)                       0x474
 ...

也可以通过 linker 的 -init 来指定而不使用默认的 _init 函数, 效果是一样的.

1.2. verbose

1.3. script

1.4. entry

1.5. gc-sections

use `gc-sections`, `-ffunction-sections`, `-fdata-sections` to remove unused symbol

[2020-11-06 Fri]

正常情况下, ld 在链接时会以 object 为单位, 把所有的同类 input section 集合成一个 section, 其中 ld 的 gc-sections 参数会导致没有用到的 input section 会被删除

gc-sections decides which input sections are used by examining symbols and relocations. The section containing the entry symbol and all sections containing symbols undefined on the command-line will be kept, as will sections containing symbols referenced by dynamic objects. Note that when building shared libraries, the linker must assume that any visible symbol is referenced. Once this initial set of sections has been determined, the linker recursively marks as used any section referenced by their relocations.

默认情况下同一个 object 中的所有函数都在同一个 input section, 导致只要有一个函数被引用, 整个 input section 被会被保存.

通过 ffunction-sections, 可以使每个函数都在它自己的 section 中, 例如 foo 函数会放在 .text.foo 中, 这样配合 gc-sections, 就可以删除没使用的函数

#include <stdio.h>

void foo() { printf("hello\n"); }
int main(int argc, char** argv) {}
$> gcc test.c
$> nm ./a.out|grep foo
0000000000001149 T foo

$> gcc -ffunction-sections test.c -c
$> readelf -S ./test.o|grep text
[ 1] .text             PROGBITS         0000000000000000  00000040
[ 5] .text.foo         PROGBITS         0000000000000000  00000046
[ 6] .rela.text.foo    RELA             0000000000000000  000002c8
[ 7] .text.main        PROGBITS         0000000000000000  0000005d

$> gcc -ffunction-sections test.c -Wl,-gc-sections
$> nm ./a.out|grep foo

1.6. nostdlib

1.7. pie

1.8. rpath

1.9. no-as-needed/whole-archive

正常情况下 -lxx 需要放在 .o 之后, 因为 libxx 是否需要链接进来取决于前面是否有缺失的符号.

gcc -lfoo test.o -o test 时, lfoo 并不会被链接, 因为处理命令行参数 lfoo 时, 当前并没有解析 test.o, 也就是没有缺失的符号需要从 foo 中链接

通过 no-as-needed, 可以强制链接后面的 so whole-archive 和 no-as-needed 类似, 但它对应的是静态库

–no-as-needed

This option affects ELF DT_NEEDED tags for dynamic libraries mentioned on the command line after the –as-needed option. Normally the linker will add a DT_NEEDED tag for each dynamic library mentioned on the command line, regardless of whether the library is actually needed or not. –as-needed causes a DT_NEEDED tag to only be emitted for a library that at that point in the link satisfies a non-weak undefined symbol reference from a regular object file or, if the library is not found in the DT_NEEDED lists of other needed libraries, a non-weak undefined symbol reference from another needed dynamic library. Object files or libraries appearing on the command line after the library in question do not affect whether the library is seen as needed. This is similar to the rules for extraction of object files from archives. –no-as-needed restores the default behaviour.

–whole-archive

For each archive mentioned on the command line after the –whole-archive option, include every object file in the archive in the link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.

Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive. Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to your link and you may not want this flag to affect those as well.

由于 -lxxx 的先后顺序很重要, 所以 Makefile 的 explicit rule 里有一个单独的 LDLIBS, 用来指定 -lxxx, 用来和 LDFLAGS 区分, 因为 explicit rule 大约是:

gcc $CPPFLAGS $CFLAGS $LDFLAGS test.o -o test $LDLIBS

以确保 -lxxx 会被放在 test.o 之后

1.10. section-start

1.11. version_script

1.12. soname

1.13. Bsymbolic

1.14. muldefs

`-z muldefs` 允许有重复的符号定义

1.15. dynamic-linker

1.16. relro

1.17. wrap

如何给重写 malloc 并调用原来的 malloc

/* main.c */
#include <stdlib.h>
int main(int argc, char** argv) {
    malloc(10);
}

/* my_malloc.c */
#include <stdlib.h>
void* __real_malloc(size_t size);

void* __wrap_malloc(size_t n) {
    printf("hello\n");
    return __real_malloc(n);
}
$> gcc test.c my_malloc.c -Wl,--wrap,malloc -static -g
$> gdb ./a.out
(gdb) disass main
Dump of assembler code for function main:
   0x0000000000401d35 <+0>:     endbr64
   0x0000000000401d39 <+4>:     push   %rbp
   0x0000000000401d3a <+5>:     mov    %rsp,%rbp
   0x0000000000401d3d <+8>:     sub    $0x10,%rsp
   0x0000000000401d41 <+12>:    mov    %edi,-0x4(%rbp)
   0x0000000000401d44 <+15>:    mov    %rsi,-0x10(%rbp)
   0x0000000000401d48 <+19>:    mov    $0xa,%edi
   0x0000000000401d4d <+24>:    callq  0x401d59 <__wrap_malloc>
   0x0000000000401d52 <+29>:    mov    $0x0,%eax
   0x0000000000401d57 <+34>:    leaveq
   0x0000000000401d58 <+35>:    retq
$> (gdb) disass __wrap_malloc
Dump of assembler code for function __wrap_malloc:
   0x0000000000401d59 <+0>:     endbr64
   0x0000000000401d5d <+4>:     push   %rbp
   0x0000000000401d5e <+5>:     mov    %rsp,%rbp
   0x0000000000401d61 <+8>:     sub    $0x10,%rsp
   0x0000000000401d65 <+12>:    mov    %rdi,-0x8(%rbp)
   0x0000000000401d69 <+16>:    lea    0x93294(%rip),%rdi        # 0x495004
   0x0000000000401d70 <+23>:    callq  0x4118f0 <puts>
   0x0000000000401d75 <+28>:    mov    -0x8(%rbp),%rax
   0x0000000000401d79 <+32>:    mov    %rax,%rdi
   0x0000000000401d7c <+35>:    callq  0x41f1f0 <malloc>
   0x0000000000401d81 <+40>:    leaveq
   0x0000000000401d82 <+41>:    retq
End of assembler dump.

通过 `Wl,–wrap,malloc`, 所有对 malloc 的调用被 ld 修改为 __wrap_malloc, 且代码中通过 __real_malloc 可以引用原来的 malloc

Backlinks

Static Linker (Static Linker > Linker Options): Linker Options

Author: [email protected]
Date: 2017-08-02 Wed 00:00
Last updated: 2024-08-19 Mon 12:15

知识共享许可协议