这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » [原创]Linker和loader

共9条 1/1 1 跳转至

[原创]Linker和loader

菜鸟
2003-03-08 03:24:42     打赏
连接器[linker]和加载器[loader]是如何工作的,目标模块是什么样的? 虽然linker和loader功能上有些重叠[overlaps],概念上却各自独立执行操作。 当加载目标模块时, 有3个主要步骤 A. 程序加载:目标模块被复制到主内存 B. 重定位:目标模块创建时,起始地址为0。然而所有目标模块都加载到自己的空间,地址不能出现重叠。重定位就是为模块的各部分指定加载地址,按指定地址调整模块的代码和数据的过程。 C. 符号解析:当存在多个模块时,需通过符号完成模块之间的相互引用。模块中的弱符号(未初始化全局量)和未定义符号,就试图用前面加载模块的符号来完成解析。 当linker运行时,需先扫描输入文件,确定段[segment]的大小,收集所有符号的定义和引用。创建段表和符号表,段表列出输入文件定义的所有段,符号表包括所有输入输出符号。Linker再利用第一次扫描所得数据,在输出地址空间,为符号指定数字地址,确定段的大小和位置;并计算出该放在输出文件的什么位置。 第二次扫描中,linker利用前面的信息来控制真正的连接过程。读取并重定位代码,替换符号引用的数字地址,按重定位的段地址来调整代码和数据的内存地址。 看下面的汇编代码,使用“eax”寄存器,将变量“a”内容传到变量“b”中。这是一个简单的重定位和符号解析的例子。假如“a”的地址为0x1234,b为引入变量。 mov a,%eax ;A1 34 12 00 00 mov %eax,b ;A3 00 00 00 00 右边为目标代码,命令1个字节,地址4个字节。因为b的地址未知,所以就填为0。 假设经过重定位,在输出文件中,模块位于0x1000,b位于0x9A12。代码就变为 A1 34 12 01 00 A3 12 9A 00 00 可以看到,因为重定位和地址解析,两个地址都被更新拉。 这个例子来源于John R..Levine写的《linkers and loades》,是一本非常好的书籍,有很多其他复杂的例子,以及连接和加载过程的细节信息。 (未完待续) from wind river techtips by amine@263.net



关键词: 原创     Linker     loader     模块     地址     符号    

菜鸟
2003-03-09 22:24:00     打赏
2楼
符号表处理 linker会读取输入模块中所有的符号表,建立连结时[link time]符号表,在连结过程中使用。有三种不同的连结时符号表:一种列出输入文件、库模块,并保持每个文件的信息;第二种有全局符号,也就是linker需要在输入文件间解析的符号。第3种符号表处理模块内部的调试符号。 如前面所述,连接分为两步完成。第一步,linker从每个输入文件读进符号表,并维护一个独立的全局量表,包括所有输入文件中定义或引用的每个符号。每次linker读输入文件,都将该文件所有的全局符号添加到符号表中,并保留符号定义或引用的位置信息。 第一步完成后,每个全局符号都有了精确的定义。第二步,Linker边创建输出文件,边解析符号。解析和重定位互相影响,因为在大多目标模块格式中,各重定位项确定程序对符号的引用。 对含有构造函数和析构函数的程序,多数linker创建指针表,指针指向来自各输入文件的函数;linker创建类似__CTOR__LIST__样的符号,作为语言启动辅助[stub],用来查找指针表和调用所有的函数。 名称修饰[name mangling] 在目标文件符号表和连接中使用的名称,经常和源代码中的名称不同。这有3个原因:避免名称冲突,名称过多(overload),类型检查。将源程序中名称转换为目标文件中名称的过程叫做名称修饰。 在C++中,可能存在很多相同名称的函数和变量,但有不同的作用范围和参数。名称修饰工作就是,给每个可能的C++对象取一个唯一的名称,而名称却变得冗长和难懂。 重定位 依据段起始地址调整程序地址的过程;解析对外部符号引用的过程;统称为重定位。 重定位有两种类型:连接时重定位和加载时重定位。前者比后者更为复杂。在加载重定位时,整个程序被看作一个大段,loader根据名义[nominal]加载地址和实际j加载地址的不同,只需要调整程序地址就行拉。而在连接时,根据段的地址和大小,不同的地址有不同的偏移量。 (未完待续) from wind river techtips by amine@263.net [align=right][color=#000066][此贴子已经被作者于2003-3-9 14:25:37编辑过][/color][/align]

菜鸟
2003-03-09 22:26:00     打赏
3楼
主机加载 vxWorks主机loader源代码位于/host/src/tgtsvr/loader(普通版本没有)。可以将源代码文件分为3类: - 一般 loadlib.c, unldlib.c, asyncldlib.c, cpluslib.c - 目标模块格式 loadaout.c, loadcoff.c, loadelf.c, loadpecoff.c, loadsom.c - 体系结构相关 aout68k.c, aoutspar.c, aoutx86.c; coffarm.c, coffi960.c; elfmips.c, elfppc.c, elfsparc.c;pecoffx86.c;somhppa.c 当你从WindSH调用loadModule,实际调用的是loadModuleAt(),text,data,bbs各区地址都为NULL,这样目标模块加载到WDB内存池中任何位置。LoadModuleAt再调用asyncLoadModuleAt()。asyncLoadModuleAt()用ioRead将目标模块读入并存储在主机内存中,并用sllPutAtTail将加载请求添加到loader线程的队列中。 目标机加载 vxWorks目标机loader源代码位于/target/src/ostool。调用序列如下。 loadModule() 调用loadModuleAt() 函数, text, data,bbs各区地址都为NULL。 loadModuleAt再调用loadModuleAtSym() 。loadModuleAtSym()再调用loadRoutine函数指针。 体系结构不同,loadRoutine也不同,可能是下面所列的一种: - aoutLdMdlAtSym - ldCoffModAtSym - ldEcoffMdlAtSym - loadElfFmtManage - ldPecoffModAtSym - ldSomCoffMdlAtSym loadRoutine执行加载,重定位和符号解析。 (未完待续) from wind river techtips by amine@263.net

菜鸟
2003-03-09 22:30:00     打赏
4楼
目标模块包含5种基本信息: - 头信息: 文件的整体信息; 代码大小,源文件名,生成日期等 - 目标代码: 包括text, data, bss 区[sections] - 重定位信息 - 符号 - 调试信息 目标模块有3种类型: - 可连接的: 包含linker需要的丰富的符号和重定位信息。 - 可执行的: 不需要任何符号,也几乎没有重定位信息。一般页对齐以允许文件被映射到地址空间。 - 可加载的: 由代码组成。可能包含完整的符号和重定位信息,以便运行时符号连接 基本的目标模块格式类型: - aout: 68K, sparc, x86 - coff: arm, i960 - elf: ppc, mips, sparc - pecoff: x86 - somcoff: hp-pa (pa-risc) a.out 目标模块格式 典型的可重定位a.out 格式: a.out头 TEXT DATA Text Reloc DataReloc 符号表 串表 当代码被重定位到不同的基地址,代码中需要修改的地方被标识出来。在可连接文件中,对未定义符号的引用也被标识。这样,当符号最终被定义时,linker才知道要将符号的值补丁到哪些地方。 符号表中每项有12字节,遵循如下格式,()中为字节数: 名称偏移(4)-类型(1)-保留(1)-调试信息(2)-值(4) text, data, bss, abs(绝对的不可重定位符号), undefined是符号表中最通常的几种符号类型。 ELF 目标模块格式 典型可重定位ELF格式: ELF头 段表 .text .data .rodata .bss .sym .rel.text .rel.data .rel.rodata .line .debug .strtab 区表 ELF头,段表和区表不作为一个区[section]。上面每个区都包括一种类型的信息,比如程序代码,初始化数据,重定位条目等。下面为各区的说明。 .text 程序代码 .data 初始化数据 .rodata 只读初始化数据 .bss 未初始化数据 .rel.text 重定位信息 .rel.data 重定位信息 .rel.rodata 重定位信息 .init 程序启动时执行的代码 .fini 程序结束时执行的代码 .rel.init 重定位信息 .rel.fini 重定位信息 .symtab 常规符号表 .dynsym 动态linker符号表 .debug 调试器用符号 .line 源代码行号和目标代码位置的对应 .comment 文档串 .got 全局偏移表[global offset table] .plt 过程连接表[procedure linkage table] from wind river techtips by amine@263.net

菜鸟
2003-03-09 22:32:00     打赏
5楼
用ld()加载目标模块的顺序很重要。若一个模块在加载时有未解析符号,后面再加载的其他模块对解析这些符号没有帮助。加载模块只能和先他加载的模块连接。例如:有两个模块:app1.o和app2.o,app1.o可以独立运行,而app2.o对app1.o中定义的符号有依赖。这种情况下,ld()会执行必要的连接操作,但是app1.o必须在app2.o之前加载。 from wind river techtips by amine@263.net

菜鸟
2003-03-10 01:10:00     打赏
6楼
<>我在主页放了本 http://amine.nease.net/docs/linker.pdf

菜鸟
2003-12-26 02:49:00     打赏
7楼
赞赞赞

菜鸟
2003-12-28 02:13:00     打赏
8楼
到ftp上找找

菜鸟
2006-01-14 05:42:00     打赏
9楼
该书非常经典!

共9条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]