跳至主要内容

Linking

We know the process of building programs are divided into two parts, compiling and linking. Linking is a process that combine different part of codes and data into one executable program. Here is a general picture:

Preprocessing -> Compiling -> Assembling -> Linking

A linker mainly does two tasks: symbol resolution, and relocation. Symbol resolution relates every symbols referenced in the target object file (both code and data) to their definition. Relocation generate an absolute address for every symbols according their relative addresses, since code starts from address 0x00 after assembling.

Every object file will contain their own symbol tables. There are symbols defined in and not in the current object file. Function and initialized variables are strong symbols, and uninitialized variables are weak symbols. Rules for symbol resolution in Unix linker are defined as followes:

Rule.1 Only one strong symbol is allowed, otherwise is a linker error.

Rule.2 If there is a strong symbol and other weak symbols, choose strong symbol.

Rule.3 If there is no strong symbol, then choose any weak symbol at random.

Once the choice is made, symbols in object files not in the object file where choosen one stays will be resolved to the choosen one, i.e, reference to the choosen one.

Several important sections in executable files' headers are: .text, .rodata, .data, .bss. .rel.text, .rel.data. Section .text contains executable machine codes, .rodata contains readonly data, while section .data and .bss contain initialized and uninitialized global variables, respectively. Section .rel.text and .rel.data contains table needed for code and data relocation respectively.

Static libraries take additional space and memory because object file needed in final executables will be linked, dynamic libraries spare space and memory at the cost of time overhead because of dynamic linking at loading times.

(this is a summary on chapter 7 of the book "computer systems, a programmer's perspective")

评论

此博客中的热门博文

知识管理的原则

寻找PKM时,看到这样一个贴子,感觉有一些原则比较有启发作用,其实重要的是方法,其次是合适的工具。所谓原则,对不同人来说也不是绝对,适合自己的就好。 个人知识管理的29个原则(转) 1、持续的学习成为个人生存和发展的基础。持续学习不一定能带来成功,但不学习一定失败;  2、信息和知识爆炸,在一段时间和时期内,学习的内容必须聚焦。起码要在一个领域内成为专家。  3、你应该学习的内容取决于你的价值观、特长、个性和目标。  4、你必须学会如何有效的评估信息和知识,所以你必须根据你的价值观、特长、个性和目标确立自己对信息和知识的“过滤器”;  5、人是知识获取的重要渠道,所以你应该知道谁最擅长什么?遇到问题时知道可以向谁学习和请教;  6、你牛了你的朋友也一定牛,建立人际资源的基础是自己的知识基础、个性和激情、自己优势的合理展示和帮助别人的意愿;  7、人际关系需要维护;捷径是找到那些愿意共享自己朋友资源的人,你也应该做这样的人;  8、信息如果不经过处理,不能称为知识。所以你存储的知识起码你应该简单看过、知道是在讲什么;  9、信息和知识存储前应该尽可能做规范化的工作,例如你做的摘要、感触、觉得最有价值的部分、将来能做什么用等等;  10、建立自己的分类字典,而不是每次想起什么就建立什么样的文件夹或者标签。分类字典,持之以恒坚持,适当调整;  11、知识存储中分类不宜过宽,过宽则等于没有分类;分类不宜过深,过深后你就不会再去看;  12、充分利用各种工具,尤其是web2.0工具做知识存储和获取工作;  13、知识存储时适当共享,听取和收集别人的意见和建议;  14、有意识的做知识显性化的工作,既方便知识传播也促进知识学习和建立人际网络;  15、知识传播中必须考虑传播的方式和效率;  16、不能用简单朴素的语言表述的知识证明你还没有深入理解;  17、多用举例子、讲故事的方法传播你的知识、见解。这个过程是你对知识的再深化过程;  18、你的知识传播的越广,你的影响力越大;  19、你的目的决定了你知识利用的方式。如果目的是要写论文,则你的知识就是明确、简洁的表达;如果是想要在市场上销售,就必须产品化、规范化或者专利化;  20、知识本身没有价值,只有被利用时才能展现其价值;  21、知识必须跟任务、项目结合起来才能发挥作用;  22、单独的一个主题的知识很难被很好的利用,...

Computer Systems: A Programmer's Perspective

Bryant, R.E所著的这本Computer Systems: A Programmer's Perspective,在国内翻译为《深入理解计算机系统》,由中国电力出版社2004出版,应该算是一本重量级的书了。从同学推荐到今天看完,足足花了有5个月的时间,虽然看得不深,但总的感觉还是不错,在这里就对它作一个总结吧。 Computer Systems表明这本书讲解的是计算机系统知识,但A Programmer's Perspective却又告诉我们它与其它书籍的不同之处,便是从程序员的角度,即偏向软件的角度,而不过多地涉及硬件内容。计算机系统本身就是一门涉及面广,内容繁多的学科,这本书不可避免地从各个角度讲解了这些内容。下面以我个人的观点进行一些总结。 第1章:计算机系统漫游 主要是对全书内容作了一个简要的概括。 第2章:信息的表示和处理 这一章主要讲解了整数与浮点数。虽然对于整数我们已经很熟悉了,但是在实际中仍会犯下各种各样的错误,书中对不同整型数间的转换及运算作出了很详细的论述。浮点数似乎一直是计算机书籍里不愿涉及的话题,对于想了解浮点数表示及浮点数运算的人来说,这部分关于浮点的描述可以作为一个很好的起点。 第3章 程序的机器级表示 对于任何一个希望了解底层的人来说,这一章可说是相当精彩的。本章主要讲解了IA32的指令集,因此以汇编为主,在控制流指令部分还将C语言及对应的汇编形式进行了对照,在调用部分还详细讲解了本地栈。最后为对浮点感兴趣的人准备了IA32中用于处理浮点的指令集。 第4章 处理器体系结构 这一章是本书中最接近硬件的部分了,从设计一个简单的处理器Y86出发并逐步完善它,一步步地引导读者理解处理器体系结构。虽然我们可能永远也不会自己设计处理器,但了解它是何工作的能有助我们理解整个计算机系统是如何工作的,比如对程序优化就很有帮助。本章首先给出了Y86的指令集,并使用一种硬件描述语言HCL对硬件的逻辑结构进行了描述,然后将指令分成取指、译码、执行、访存、写回、更新PC六个阶段,给出了每条指令的每一部分的操作内容,并对每一部分的硬件实现分别进行了讨论。显然,这种顺序的实现过程是低效的,本章的后面部分便围统着流水线的实现以及遇到的问题展开了论述。 第5章 优化程序性能 本章介绍了一些代码优化的内容,如前面所说,只有理解了处理器系...

MIPS中断在uboot下的实现

摘要:本文阐述了MIPS中断在u-boot下的整个实现过程,并对实践中遇到的问题进行了分析,特别分析了u-boot所采用的位置无关代码及汇编实现的特殊性,对类似应用具有较好的借鉴意义。 随着Linux嵌入式系统的广泛使用,使用uboot作为bootloader越来越多。u-boot发源于ppc架构8xx系列,对ppc架构的支持最为完善,而对其它架构的支持情况则要弱一些,以MIPS为例,目前的最新版本u-boot-2010.03仍然不支持异常和中断的处理。缺少中断机制带来了一些麻烦,比如不能支持统一的点灯规范,更重要的是在无中断的单任务环境下,协议栈缺乏有效的超时重传机制,在复杂的框上环境中,单板容易假死在boot中。 本文描述了MIPS架构中断在u-boot下的实现过程,并对遇到的问题进行了分析和总结。我们首先讨论了通用的异常处理过程,然后结合代码实现对异常处理代码进行了阐述,最后对调试过程中出现的问题进行了分析。u-boot有其自身的特点,本文同时也对位置无关代码进行了一定的分析。 中断处理在实现上并不复杂,其处理过程可以简单地划分为下面几个步骤: 1. 保存中断上下文 2. 处理中断并应答 3. 恢复中断上下文 4. 使能中断 这种处理方式比较简单,整个中断处理是在中断环境中完成的,没有中断嵌套。对于VxWorks这样的实时操作系统,需要允许高优先级中断抢占低优先级中断,因此它的处理步骤要复杂一些,在进入中断后,只保存少量的易失性寄存器,并尽早地开启中断。因为我们只需要实现简单的定时器,所以就按照最简单的方法实现。 MIPS CPU产生中断时,CPU跳转到EBASE+0x180或者0x200(取决于COP0 Cause.IV的设置。IV=1时,中断使用0x200入口,IV=0时,中断使用通用异常入口0x180)处开始执行中断处理程序。一般来说,异常向量处的大小都是受限的,MIPS也不例外,每个异常向量的大小不能超过0x80的长度,如果要在这里进行上下文保存,空间是不够的。惯例是在这里设一处跳转,到一个大小不受限的地方开始保存上下文。 上下文的保存可以分为两种实现,一种是使用当前任务的栈,一种是使用专门的栈,对于只工作在内核态的boot来说,这两者在使用上并无差别。理论上,开辟专门的栈可靠性更高,不容易被破坏。对于不同的架构,上下文的含义不同,对MIPS而言,上下...