复习
本次课回答的问题
本次课主要内容
可执行文件
/usr/include/elf.h
加载器 (loader)
加载操作系统内核?
bootmain.c (i386/x86-64 通用)
loader-static.c, bootmain.c 和 Linux 有本质区别吗?
make menuconfig
(生成 .config 文件)make bzImage -j8
编译结果
__startup_64
: RTFSC; 调试起来!fs/binfmt_elf.c
: load_elf_binary
让我们愉快地打个断点……
script/gen_compile_commands.py
@
, #
)随着库函数越来越大,希望项目能够 “运行时链接”。
减少库函数的磁盘和内存拷贝
大型项目的分解
和 ELF battle 的每一年:讲着讲着就讲不下去了
GOT[0]
, GOT[1]
, ... ???换一种方法
动态链接的符号查表就行了嘛 。
DL_HEAD
LOAD("libc.dl") # 加载动态库
IMPORT(putchar) # 加载外部符号
EXPORT(hello) # 为动态库导出符号
DL_CODE
hello:
...
call DSYM(putchar) # 动态链接符号
...
DL_END
.dl
文件配齐全套工具链编译器
binutils
和最重要的
头文件
“全家桶” 工具集
示例代码
存储保护和加载位置
允许自由指定加载器 (而不是 dlbox)
空间浪费
其他:不那么重要
#define DSYM(sym) *sym(%rip)
DSYM 是间接内存访问
extern void foo();
foo();
一种写法,两种情况
我们的 “符号表” 就是 Global Offset Table (GOT)
统一静态/动态链接:都用静态!
putchar@PLT:
call DSYM(putchar) # in ELF: jmp *GOT[n]
main:
call putchar@PLT
你会发现和我们的 “最小” 二进制文件几乎完全一样!
00000000000010c0 <printf@plt>:
10c0: endbr64
10c4: bnd jmpq *0x2efd(%rip) # DSYM(printf)
10cb: nopl 0x0(%rax,%rax,1)
00000000000011c9 <main>:
...
1246: callq 10c0 <printf@plt>
如果我们想要引用动态链接库里的数据?
stdout/errno/environ 的麻烦
当然是做实验了!
本次课回答的问题
Take-away messages