范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

计算机大佬让你彻底了解ampampquot深入理解计算机系统ampampquot

  前言
  当我们点击Xcode的运行按钮时,你会注意到在界面顶端的提示栏上会出现"Building"的字样,紧接着会出现"Linking"的字样,我们知道Building是编译过程,那这个Linking(链接)是什么过程呢?本文将对链接过程做一个讲解,了解链接的过程,可以帮助你理解计算机系统的底层原理,并解答你平时关于计算机怎样识别并执行程序的一些疑惑。另外,本文也是后续篇章的基础,我们会由链接的知识延展出Mach-O文件、fishhook原理以及hook objc_msgSend的知识讲解。链接的基本概念
  链接(linking)是将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载(复制)到内存并执行。
  链接可以执行与编译时(complie time),也就是源代码被翻译成机器代码时;也可以执行于加载时(load time),也就是在程序被加载器(load-er)加载到内存并执行时;甚至可以执行在运行时(run time),也就是由应用程序来执行。在早期的计算机系统中,链接是手动执行的。在现代系统中,链接是由叫做连接器(linker)的程序自动执行的。链接的作用
  链接器使分离编译成为可能,我们不用将一个大型的应用程序组织为一个巨大的源文件,而是可以把它分解为更小、更好管理的模块,可以独立地修改和编译这些模块。当我们改变这些模块中的一个时,只需简单地重新编译它,并重新链接应用,而不必重新编译其它文件。
  下面的讨论基于这样的环境:一个运行Linux的x86-64系统,使用标准的ELF-64目标文件格式。编译器驱动程序
  下面的C语言示例程序,由两个源文件组成,main.c和sum.c。main函数初始化一个整数数组,然后调用sum函数来对数组元素求和。// sum.c  int sum(int *a, int n) {     int s = 0;     for (int i = 0; i < n; i++) {         s += a[i];     }     return s; }  // main.c  int array[2] = {1, 2};  int main() {     int val = sum(array, 2);     return val; }
  大多数的编译系统会提供编译器驱动程序(compile driver),包含语言预处理器、编译器、汇编器和链接器。首先编译器驱动程序会对main.c与sum.c文件的源代码进行翻译,翻译过程如下:
  image
  其中,main.o称为可重定位目标文件。
  之后,编译系统会运行链接器ld,将main.o和sum.o以及一些必要的系统目标文件组合起来,创建一个可以执行目标文件,这个过程是静态链接,过程如下:
  image
  再之后,操作系统会调用加载器(loader),将可执行文件prog中的代码和数据复制到内存中,然后执行。静态链接
  静态链接器(static linker)以一组可重定位目标文件作为输入,生成一个完全链接的、可以加载和运行的可执行目标文件。输入的可重定位目标文件由各种不同的代码和数据节(section)组成,每一节都是一个连续的字节序列。指令在一节中,初始化了的全局变量在另一个节中,而未初始化的变量又在另外一节中。
  为了构造可执行文件,链接器必须完成两个重要的任务:符号解析(symbol resolution)。目标文件定义和引用符号,一个个符号对应一个函数或一个全局变量或一个静态变量(即C语言中以static属性声明的变量)。符号解析的目的是将每个符号引用正好和一个符号定义关联起来。重定位(relocation)。编译器和汇编器生成从地址0开始的代码和数据节。链接器通过把每个符号定义与一个内存位置关联起来,从而重定位这些节,然后修改所有对这些符号的引用,使它们指向这个内存位置。
  目标文件纯粹是字节块的集合,这些块中,有些包含程序代码,有些包含数据,而有些则是引导链接器和加载器的数据结构。链接器将这些块连接起来,确定被连接块的运行时位置,并且修改代码和数据块中的各种位置。目标文件
  目标文件有三种形式:可重定位目标文件。包含二进制代码和数据,其形式可以在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件。可执行目标文件。包含二进制代码和数据,其形式可以被直接复制到内存并执行。共享目标文件。一种特殊类型的可重定位目标文件,可以在加载或者运行时被动态的加载进内存并链接。动态库就是这种形式的。
  目标文件的生成方式:编译器和汇编器生成可重定位目标文件(包括共享目标文件)。链接器生成可执行目标文件。
  目标文件的格式:在iOS和MacOS-X中,目标文件的格式是Mach-O格式。X86-64 Linux和Unix系统使用可执行可连接格式ELF。可重定位目标文件
  image.png
  下上展示了一个典型的ELF可重定位目标文件的格式。ELF头包含很多信息,包括生成该文件的系统的字节大小,字节顺序,ELF头的大小,目标文件的类型,机器类型等等。节头部表描述了不同节的位置和大小。
  加载ELF头和节头部表的是节:.text:已编译程序的机器代码。.rodata:只读数据,比如 printf语句中的格式串和开关语句的跳转表。.data:已初始化的全局和静态C变量。局部C变量在运行时被保存在栈中,既不出现在,data节中,也不出现在.bss节中.bss:未初始化的全局和静态C变量,以及所有被初始化为0的全局或静态变量。在目标文件中这个节不占据实际的空间,它仅仅是一个占位符。目标文件格式区分已初始化和未初始化变量是为了空间效率:在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。运行时,在内存中分配这些变量,初始值为0。.symtab:一个符号表,它存放在程序中定义和引用的函数和全局变量的信息。一些程序员错误地认为必须通过-g选项来编译一个程序,才能得到符号表信息。实际上,每个可重定位目标文件在. symtab中都有一张符号表(除非程序员特意用 STRIP命令去掉它)。然而,和编译器中的符号表不同, symtab符号表不包含局部变量的条目。.rel.text:一个.text节中位置的列表,当链接器把这个目标文件和其他文件组合时,需要修改这些位置。一般而言,任何调用外部函数或者引用全局变量的指令都需要修改。另一方面,调用本地函数的指令则不需要修改。注意,可执行目标文件中并不需要重定位信息,因此通常省略,除非用户显式地指示链接器包含这些信息。.rel.data:被模块引用或定义的所有全局变量的重定位信息。一般而言,任何已初始化的全局变量,如果它的初始值是一个全局变量地址或者外部定义函数的地址,都需要被修改。.debug:一个调试符号表,其条目是程序中定义的局部变量和类型定义,程序中定义和引用的全局变量,以及原始的C源文件。只有以-g选项调用编译器驱动程序时,才会得到这张表。.line:原始C源程序中的行号和.text节中机器指令之间的映射。只有以-g选项调用编译器驱动程序时,才会得到这张表。.strtab:一个字符串表,其内容包括. symtab和, debug节中的符号表,以及节头部中的节名字。字符串表就是以nu11结尾的字符串的序列。符号和符号表
  每个可重定位目标模块(目标文件)m都有一个符号表,它包含m定义和引用的符号的信息。在链接器的上下文中,有三种不同的符号:由模块m定义并能被其它模块引用的全局符号。这些符号对应于非静态的C函数和全局变量。由其它模块定义并被模块m引用的全局符号。这些符号称为外部符号,对应于在其它模块中定义的非静态C函数和全局变量。只被模块m定义和引用的局部符号。它们对应于带static属性的C函数和全局变量。这些符号在模块m中任何位置都可见,但是不能被其它模块引用。
  .symtab中的符号表不包含非静态程序变量的任何符号,这些程序变量符号在栈中被管理,链接器对此类符号不感兴趣。如何解析多重定义的全局符号
  链接器的输入是一组可重定位目标模块。每个模块定义一组符号,有些是局部的(只对定义该符号的模块可见),有些是全局的(对其他模块也可见)。如果多个模块定义同名的全局符号,会发生什么呢?下面是 Linux编译系统采用的方法。
  在编译时,编译器向汇编器输出每个全局符号,或者是强( strong)或者是弱(weak),而汇编器把这个信息隐含地编码在可重定位目标文件的符号表里。函数和已初始化的全局变量是强符号,未初始化的全局变量是弱符号。
  根据强弱符号的定义,Linux链接器使用下面的规则来处理多重定义的符号名规则1:不允许有多个同名的强符号。规则2:如果有一个强符号和多个弱符号同名,那么选择强符号。规则3:如果有多个弱符号同名,那么从这些弱符号中任意选择一个。静态库
  迄今为止,我们都是假设链接器读取一组可重定位目标文件,并把它们链接起来,输出一个可执行目标文件。实际上,所有的编译系统都提供一种机制,将所有相关的目标模块打包成一个单独的文件,称为静态库。静态库可以用做链接器的输入,当链接器构造一个输出的可执行目标文件时,它只复制静态库里被应用程序引用的目标模块,这就减少了可执行文件在磁盘和内存中的大小。在Linux系统中,静态库由后缀.a标识。重定位
  一旦链接器完成了符号解析这一步,就把代码中的每个符号引用和正好一个符号定义(即它的一个输入目标模块中的一个符号表条目)关联起来。此时,链接器就知道它的输入目标模块中的代码节和数据节的确切大小。现在就可以开始重定位步骤了,在这个步骤中,将合并输入模块,并为每个符号分配运行时地址。重定位由两步组成:重定位节和符号定义。在这一步中,链接器将所有相同类型的节合并为同一类型的新的聚合节。例如,来自所有输入模块的.data节被全部合并成一个节,这个节成为输出的可执行目标文件的.data节。然后,链接器将运行时内存地址赋给新的聚合节,赋给输人模块定义的每个节,以及赋给输人模块定义的每个符号。当这一步完成时,程序中的每条指令和全局变量都有唯一的运行时内存地址了。重定位节中的符号引用。在这一步中,链接器修改代码节和数据节中对每个符号的引用,使得它们指向正确的运行时地址。要执行这一步,链接器依赖于可重定位目标模块中称为重定位条目(relocation entry)的数据结构。
  当汇编器生成一个目标模块时,它并不知道数据和代码最终将放在内存中的什么位置,它也并不知道这个模块引用的任何外部定义的函数或者全局变量的位置。所以,无论何时汇编器遇到对最终位置的目标引用,它就会生成一个重定位条目,告诉链接器在将目标文件合并成可执行目标文件时如何修改这个引用。可执行目标文件 与 加载可执行目标文件
  见《深入理解计算机系统》动态链接共享库
  静态库由一些缺点:静态库需要定期维护和更新;每个程序都会使用一些通用的标准函数,在运行时,这些函数的代码会被复制到每个运行进程的文本段中,在一个运行上百个进行的典型系统上,这是对内存资源的浪费。
  共享库(shared library)是致力于解决静态库缺陷的一个现代创新产物。共享库是一个目标模块,在运行或加载时,可以加载到任意内存地址,并和一个在内存中的程序链接起来。这个过程称为动态链接,是由一个叫做动态链接器(dynamic linker)的程序来执行的。在Linux系统中,共享库通常由.so后缀标识。
  共享库以两种不同的方式来共享的。首先,在任何给定的文件系统中,对于一个库只有一个.so文件。所有引用该哭的可执行目标文件共享这个.so文件中的代码和数据,而不是像静态库的内容那样被复制和嵌入到引用它们的可执行文件中。其次,在内存中,一个共享库的.text节的一个副本可以被不同的正在运行的进程共享。
  image.png

张国荣和梅艳芳离世后,赵文卓为何消失了?去年国庆,赵文卓一段花式舞剑,空中踢刀的视频,让人看得热血沸腾,让国人见识了一把什么叫中国功夫登上热搜,没多久便燃爆整个互联网。这让无数人尖叫的同时也让人感到困惑,似乎很久没有看到成龙年轻放荡感情,出轨,防备老婆20年,他依然很成功说到成龙,大家都不陌生了。成龙的电影在那个年代堪称经典,武打戏非常精彩,称之为功夫之王,是中国第一个走上好莱坞的明星,现在已经是世界巨星了,前年还获得了奥斯卡终身成就奖。无论是在国坎爷新娇妻是金卡戴珊粉丝吧!穿同款挂脖紧身衣,勒出双层游泳圈坎爷的行事作风真是一如既往的让人看不透,自从跟金卡戴珊离婚之后,他的桃色绯闻就没有断过,而且约会对象不少都是模特,身材美貌全都在线。坎爷未婚妻身材真辣啊!穿挂脖紧身衣勒出游泳圈,蜜本以为吴刚是一张王牌,没想到是狂飙败笔最近的这个狂飙,似乎在热度方面有些不太行。作为开年来最强阵容的刑侦剧,开播之前狂飙可谓是承载着诸多希望的,毕竟是双男主剧且两大男主都是大咖,影帝张译,以及同样演技不俗的张颂文。配角2008年,她在奥运开幕式彩排时摔成瘫痪,如今已是北舞教授意外的不幸常常是财富不能弥补的。塞万提斯唐吉诃德央视春晚,一直以来都是收视率极高的节目,大多数人在除夕夜,都会和家人一起观看春晚。遍布全世界的海外华人,对春晚也非常关注。那些登上春美人胚子90后马凡舒入选央视半年就主持春晚引言2023央视春晚主持人阵容公布,年仅29岁的马凡舒第二次出现在春晚主持人名单中。美人胚子90后马凡舒入选央视半年就主持春晚,从足球节目一步跨到春晚舞台。朋友们,大家好,玉兔呈祥2023新年愿望壮成刘亦菲刘亦菲主演的去有风的地方日前正在热播,天仙也逃不过被网友指责发胖身材走形膀大腰圆太壮了!但也有不少网友表示这才是正常的女生身材,不要将女生身材过于妖魔化了那今天我们就带大家一起看看甘比带俩女儿看演唱会,4岁女儿手舞足蹈很兴奋,刘銮雄全程陪伴韩国女团BLACKPINK来香港开演唱会,演出只有三场,早在门票发售期就已经被一抢而空,出现了一票难求的局面。最令人意外的是,BLACKPINK的演唱会竟然在香港名媛圈,名人圈掀起我的科学观杨玉良让科学造福人类是永恒的追求另一方面,科学的成功也让部分科学家群体莫名地狂妄,技术的成功也导致部分科学家天真地认为这个世界就是按照他的那门学科的规律在运行。杨玉良IC资料图作为一个从事了数十年科学研究和科学教电讯报加纳乔接近与曼联续约,滕哈赫希望给他涨薪但不至于太多直播吧1月18日讯电讯报报道,加纳乔接近与曼联完成续约。加纳乔目前的合同将持续到2025年6月,而不是外界所认为的下赛季末到期,但曼联正在与这位18岁阿根廷边锋就一份新的涨薪合同进泰晤士独家格雷泽对曼联估价仍超50亿,阿联酋方面或出价虎扑01月18日讯泰晤士报著名记者MattDickinson,MattLawton独家透露了英力士老板拉特克利夫参与曼联投标的最新细节。在这一阶段,各方必须签署协议,以查看机密财务
4位顶流明星燃爆王牌!沈腾的落寞,贾玲的不屈,令人唏嘘同样是搭档,马丽与沈腾如同挚爱的手足,而贾玲与沈腾则像是知心的朋友。王牌对王牌第八期中,贾玲面对沈腾的一声疑问,沈腾看向贾玲澄澈的眼神,足以说明,最高级的交流是你说的我都懂。王牌对昔日夫妻现状反差大汪小菲开饭店赔本?大S秀与具俊晔同款纹身看点疫情当前,受冲击最大的行业应该是餐饮业了。近日,有媒体爆料汪小菲在直播中声泪俱下,感叹自己目前太难了。媒体还称汪小菲投资1个亿开了3家饭馆,如今都在赔本。面对种种传闻,汪小菲在霍启刚郭晶晶一家五口享受家庭日夫妻俩与子女吃饭玩轮滑很快乐霍启刚最近难得经常更新社交账号,他晒出一家人的温馨互动。原来他们一家五口最近就出去享受家庭日。夫妻俩带子女出去吃饭,还罕见曝光了大儿子和女儿的长相,随后带着子女去玩轮滑。一年一度的同样是演被扇耳光,把周迅和唐嫣Baby放在一起,差距就出来了每部影视剧中,都会产生许多名场面,如果要选出让观众看着特别过瘾的场景,相信掌掴戏一定榜上有名!虽然同为打耳光的戏码,但大家的表演也是各不相同有人梨花带雨,惹人怜爱有人呆若木鸡,让人iOS微信8。0。20又有新功能,遗憾没有群禁言微信又有新变化?确实是真的,前天提到,安卓版微信8。0。22版本中上线性能检测工具功能,可实现浮窗查看手机温度和利用率,不过!此功能仅限制于安卓设备,而iOS系统上是无法实现的。因卢伟冰上手redmiNote11T,小米手环7同步亮相丨谁会首发台积电8昨天晚上卢伟冰发布了一条微博,小尾巴显示来自redmiNote11T,这波也是预热的预热。不出意外的话,新机很快就会和我们见面了。作为Note系列中主打性能的一代,这回的新机在名字买安卓手机别抠搜,4款12GB256GB超值手机推荐,能选大就不选小买安卓手机别抠搜,4款12GB256GB超值手机推荐,能选大就不选小。第一款华为Mate40Pro优势麒麟9000功耗低,后置徕卡四摄,影像实力处于行业第一梯队。搭载麒麟9000处截至2022年五月,天玑9000手机共四款,理性分析优劣让你不会选错截至2022年五月,天玑9000手机共四款,理性分析优劣让你不会选错。第一款redmiK50Pro优点2K屏高赫兹刷新率续航很实用,充电20分钟就能搞定。缺点拍照一般采用了一块6。美联储带来大动荡,人民币会遭受什么影响?新兴经济体总体受挫美联储兑现了它的诺言,加息了50个基点。加息当天,美国股市就开始大涨,可是,就在第二天,股市又开始连续大跌,把周三的涨幅全部跌完了,同时,美国三大股指,道琼斯指数纳斯达克综合指数标张亮儿子女友闺蜜发声承认两人是恋爱关系,并公开女方家庭背景5月9日网络上突然流出张亮儿子天天与一名女孩子的多张亲密合照,照片中,天天跟女孩牵手,搂抱,还做出疑似亲吻的动作,画面气氛给人感觉特别暧昧。天天2007年11月12日出生,今年才只宋丹丹儿媳住20万月子中心!全家合影笑开花,4岁大儿子虎头虎脑饿了吗?戳右边关注我们,每天给您送上最新出炉的娱乐硬核大餐!5月10日,某月子中心晒出一则巴图与老婆博谷接受采访的视频,引发外界热议。视频最开始,巴图带着家人照了一张全家福,宋丹丹