模式(4选1)
-no-pie
(default): 生成position-dependent executable。要求最宽松,源文件可用-fno-pic,-fpie,-fpic
编译-pie
: 生成position-independent executable。源文件须要用-fpie,-fpic
编译-shared
: 生成position-independent shared object。最严格,源文件须要用-fpic
编译-r
: relocatable link,保留relocations
-fno-pic,-fno-PIC,-fpie,-fPIE
是同义的。-fpic,-fPIC
分别叫做small PIC、large PIC,在32-bit PowerPC和Sparc上有代码生成差异(这两种是即将退出历史舞台的架构)。大多数架构没有差异。
-fpie,-fPIE
分别叫做small PIE、large PIE,在PIC基础上引入了一个优化:编译的.o只能用于可执行档。参见下文的-Bsymbolic
。
容易产生混淆的是,编译器driver提供了几个同名选项:-no-pie,-pie,-shared,-r
,作用是传递给选项给链接器。
GCC 6引入了configure-time选项--enable-default-pie
:启用该选项的GCC预设-pie
和-fPIE
。现在,很多Linux发行版都启用了该选项作为基础的security hardening。
符号相关
--export-dynamic
shared objects预设导出所有non-local STV_DEFAULT/STV_PROTECTED
定义。可执行档可用--export-dynamic
模拟shared objects行为。
下面描述可执行档里一个符号被导出的规则:
- non-local
STV_DEFAULT/STV_PROTECTED
- 未定义,或指定了
--export-dynamic
,或被--dynamic-list/--export-dynamic-symbol-list/--export-dynamic-list
匹配,或被某个链接时shared object的STV_DEFAULT
undefined symbol引用
最后一个条件的意义是:如果可执行档定义了在某个链接时shared object引用了一个符号,那么链接器需要导出该符号,使得运行时该shared object的undefined符号可以绑定到可执行档中的定义。
-Bsymbolic
and --dynamic-list
ELF中,non-local STV_DEFAULT
的定义的符号在一个shared object预设会被preempt(interpose),即运行时该定义可能被可执行档或另一个shared object中的定义替换。
可执行档中的定义是保证non-preemptible (non-interposable)的。-fPIC
编译的程序被认为可能用于shared object,引用模块(可执行档或一个shared object被成为一个模块)内的定义预设会有不必要的开销:GOT或PLT的间接引用开销。
链接器提供了-Bsymbolic
、-Bsymbolic-functions
、version script和--dynamic-list
等几种机制使部分符号non-preemptible,获得和与-no-pie,-pie
相似的行为。
-Bsymbolic
: 所有定义的符号non-preemptible-Bsymbolic-functions
: 所有定义的STT_FUNC
(函数)符号non-preemptible--dynamic-list
: 蕴含-Bsymbolic
,但被列表匹配的符号仍为preemptible。--dynamic-list
也可用于-no-pie/-pie
,但含义不同,表示导出部分符号。我认为--dynamic-list
设计成双重含义容易产生困惑和误用
上述选项会使很多符号non-preemptible。GNU ld 2.35和LLD 11可以用--export-dynamic-symbol=glob
使部分符号保持原来的preemptible状态。GNU ld 2.35另外提供--export-dynamic-symbol-list
。
-soname
设置生成的shared object的dynamic table中的DT_SONAME
。
链接器会记录链接时shared objects,在生成的可执行档/shared object的dynamic table中用一条DT_NEEDED
记录描述每一个链接时shared object。
- 若该shared object含有
DT_SONAME
,该字段提供`DT_NEEDED的值 - 否则,若通过
-l
链接,值为去除目录后的文件名 - 否则值为路径名(绝对/相对路径有差异)
比如:ld -shared -soname=a.so.1 a.o -o a.so; ld b.o ./a.so
,a.out
的DT_NEEDED
为a.so.1
。如果第一个命令不含-soname
,则a.out
的DT_NEEDED
为./a.so
。
--as-needed
防止一些没有用到的链接时shared objects留下DT_NEEDED
。
--as-needed
和--no-as-needed
是position-dependent选项,影响后面命令行出现的shared objects。一个shared object is needed,如果下面条件之一成立:
- 在命令行中至少一次出现在
--no-as-needed
模式下 - 定义了一个被.o引用的符号且non-weak。也就是说,weak定义仍可能被认为是unneeded