Re: [问题] 连结&加载器,分段分页,Binding关系

楼主: cole945 (跶跶..)   2015-07-11 23:13:31
※ 引述《mshockwave (夏克维夫)》之铭言:
: ※ 引述《gigigigi (gigigigi)》之铭言:
: : 何谓Binding
: : Def: 决定程式执行的起始位址。
: : 即:程式要在内存的哪个地方开始执行。
好奇问一下, 这个定义是哪来的?
就如 mshockwave 所说, 一般讲 binding 是指 name binding.
而 binding time 就是指什么时候决定 "name" 与他 "所指之事"
算是较 high-level 的事情, 偏软件的问题, 虽然是跟位址有关,
但其实位址本身不是重点, 和 OS 也比较没有直接关系,
这里的定义不太正确, 所以后面的讨论好像整个歪掉 orz
: : 可能的Binding时期有三个:
: : 1. Compiling Time
: : 2. Loading Time
: : 3. Execution Time
: : 3-1 : Dynamic Binding
: : 3-2 : Dynamic Loading
: : 链接器( Linker )是把不同部分的代码和数据,收集、组合成为一个可加载、可执行的文
: : 件。
: : 加载器( Loader )把可执行文件从外存装入内存并进行执行
补充一下, 平常讲 loader, 一般应该是指 dynamic linker,
在 load time 时 resolve symbol 与 address 的东西.
相对于 static 的 linker, 是 link-time 时 resovle symble
你这边讲的 loader 是指把 executable 从 file system 放到 memory 的东西,
并不会做 symbol resolving, 功能比较单纯. 一般 loader 不是指这个.
loader (dynamic linker) 在 GNU/linux 是 ld.so 或 ld-linux.so
linker 像是 GNU binutils 里的 ld 或 gold (gold linker)
你提到的 loader 会是想 linux kernel 的 binfmt_elf 之类的东西,
http://lxr.free-electrons.com/source/fs/binfmt_elf.c
还有像 binfmt_script 是 linux 用来 load shell script 执行的东西
: : MMU : 分段 + 分页
: : 分段 - 逻辑位址 -> 线性位址
: : 分页 - 线性位址 -> 实体位址
: : _________________________________________________________________________________
: : 我被上面情况给搞的有点乱 , 有下面几点疑惑
: : 1.
: : Binging 三个时期程式位址都算是虚拟位址?
: 是的 除非你玩的是没MMU的处理器
: : Compiling Time 位址是由编译器计算出来?
: 不算是 其实是由连结器那边设定的
: : Loading Time 是由 加载器 计算出位址?
: : Execution Time : 位址是 Local Address + Base Register ?
承前面所说, binding 并不是在指位址上的问题
拿这一小段 C code 来说
static int foo (int a, int b) {
return a + b;
}
int bar () {
return foo (1, 2);
}
int qux () {
return bar ();
}
当讲 xxx-time 做 binding, 也就是说在 xxx-time 后, 这个 binding 就不能再改变
但是可以通过重新 xxx 改变 binding.
"通常" 越早 binding 的话, 效率越好, overhead 越低, optimization 越容易介入
* compile-time
bar call foo, 静态就能决定是上面那个 static int foo
例如这个阶段可以做 inline optimization.
但若如果 foo 的内容改了, 那就只有重新编译一途, 不然 bar 会和 foo 不一致
* link-time,
现在程式通常会分档编译, 如果不在同一个档有定义,
那可能在 link-time 从其他的 .o 或 .a 系结
* load-time
可以想成从程式 load 到 memory, 到他真的能开始跑前的时间.
例如, 程式中有用到 libc.so (standard C library) 的东西 (printf, etc),
那就是 load-time 才会决定要 call 哪个版本.
这时才决定的东西, 可以透过重新执行来改变 binding,
例如 printf 有 bug, 可以更新 libc.so 再重新执行,
或是可以透过 LD_PRELOAD 来影响 ld.so (loader) 要使用哪个 shard object
来的定义.
另外, qux call bar, 与 bar 之间的 binding, 在现在 GNU/Linux toolchain
的情况下, 若是 position indepedent code (PIC) 的 shared object
会是 load-time, 而不是 link-time.
* execution-time, 又指 run-time
是指程式正在 run 到时才能知道决定的, 不同语言的状况很不一样,
例如像 C++ 的 virtual function.
load-time 和 run-time 有时况状很像, 但还是有差异.
很多 script 类的 language 可以直接呼叫 foo function,
foo funtion 根本就不存在 (例如 typo 的 bug), 但 run 到时才会跟你
抱怨找不到 foo. 若是 load-time 做 binding, 就会在一开始执行时就
说无法 resolving foo
而一般 C/C++ 的 PIC code 通常会经过 GOT/PLT 查表来执行,
但 run-time 查 vtable 的状况 (overhead) 类似.
但能 optimize 的策略方法不同, load-time 在程式一开始就决定了不会改变,
若用基本的 JIT 就可以避开这个 overhead. 但 run-time 的 overhead
可能就要再透过 run-time profile 和 inline-cache 等方式
: 小弟不才 可能不完全正确 但其实元PO问的事情没那么复杂
: 用一句话回答的话就是:把一切交给虚拟位址就对了!
: 基本上会考虑到实体位址的就只有一位:核心
: 包括编译器连结器在内 都是用虚拟位址在思考
: 而我刚刚讲的 编译完的位址 其实是由叫做linker script的东西设定的
: 这些script是ld在编译的链结时期读取的
: (script路径可由 ld
作者: cobrasgo (人鱼线变成鲔鱼线,超帅)   2015-07-16 21:59:00
搞compiler的,我要跪着看文章了…

Links booklink

Contact Us: admin [ a t ] ucptt.com