解析GNU linker options
2020-11-15 17:00:00 Author: maskray.me(查看原文) 阅读量:272 收藏

模式(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.soa.outDT_NEEDEDa.so.1。如果第一个命令不含-soname,则a.outDT_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

文章来源: http://maskray.me/blog/2020-11-15-explain-gnu-linker-options
如有侵权请联系:admin#unsafe.sh