PHDRS
PHDRS 命令仅仅在生成 ELF 目标文件时有效。ELF 目标文件格式用 program headers 程
序头 (程序头内包含一个或多个 segment 程序段描述) 来描述程序如何被载入内存。可
以使用 objdump -p 命令查看。
当操作系统执行 ELF 目标文件格式的程序时,系统加载器通过读取程序头信息以通知如
何将程序加载到内存。在链接脚本内不指定 PHDRS 命令时,链接器能够很好的创建程序
头,但是有时需要更精确的描述程序头,那么 PHDRS 命令就可以派上用场。注意,一但
在链接脚本内使用了 PHDRS 命令,那么链接器仅仅会创建 PHDRS 命令指定的信息,所以
使用时须谨慎。
FILEHDR, PHDRS, AT, FLAGS 为关键字
NAME
程序段名,此名字可以与符号名,section 名,文件名重复,因此它在一个独立的名字空
间内。此名字只能在 SECTIONS 命令内使用。一个程序段可以由多个可加载的 section
组成。通过输出 section 描述段的属性 PHDRS 可以将输出 section 加入一个程序段这
里指的是 PHDRS 中的 PHDRS, PHDRS 为段名。在一个输出 section 描述内可以多次使
用 PHDRS 命令,也既可以将一个 section 加入到多个程序段。如果在一个输出
section 描述内指定了 PHDRS 属性,那么其后的输出 section 描述将默认使用该属性,
除非它也定义了 PHDRS 属性。当然当多个输出 section 属于同一程序段时可以简化书写。
TYPE
在 TYPE 属性后存在 FILEHDR 关键字,表示该段包含 ELF 头信息。TYPE 可以使一下八
种形式:
-
PT_NULL 0
表示未被使用的程序段。
-
PT_LOAD 1
表示该程序段在程序运行时应该被加载
-
PT_DYNAMIC 2
表示该程序段包含动态链接信息
-
PT_INTERP 3
表示该程序段内包含程序加载器的名字,在 linux 下常见的程序加载器是
ld-linux.so.2
-
PT_NOTE 4
表示该程序段内包含了程序的说明信息
-
PT_SHLIB 5
一个保留的程序头类型,没有在 ELF ABI 文档内定义。
-
PT_PHDR 6
表示该程序段包含程序头信息
EXPRESSION 表达式值
以上每个类型对应一个数字,该表达式定义一个用户自定义的程序头。
AT(ADDRESS)
AT(ADDRESS) 属性定义该程序段的加载位置 (LMA). 该属性将覆盖该程序段内的
section 的 AT() 属性。
FLAGS
默认情况下,链接器会根据该程序段包含的 section 的属性设置 FLAGS 标志,该标志
用于设置程序段描述的 p_flags 域。
一个简单的例子:
PHDRS 与 SECTIONS 之间的层级关系:
e.g. 三个源文件 DemoA.c,DemoB.c 和 DemoC.c,其中 DemoA.c 引用 DemoA.c 和
DemoB.c 里面的函数,使用 GCC 生成独立的目标文件 DemoA.o,DemoB.o 和 DemoC.o。
ld 使用链接脚本 Demo.lds, 并且在 Demo.lds 里面通过 PHDRS 关键字,以此来创建输
出文件的 ELF HEADERS:
DemoA.c
DemoB.c
DemoC.c
Demo.lds
使用如下命令进行编译和链接:
通过上面的运行数据可知,输出 ELF 文件的 Program Header 区域已经添加了指定的
HEADER 信息。
附录
BiscuitOS Home
BiscuitOS Driver
BiscuitOS Kernel Build
Linux Kernel
Bootlin: Elixir Cross Referencer
赞赏一下吧 🙂