深入浅出计算机组成原理
徐文浩
bothub 创始人
70432 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 62 讲
深入浅出计算机组成原理
15
15
1.0x
00:00/00:00
登录|注册

08 | ELF和静态链接:为什么程序无法同时在Linux和Windows下运行?

合并目标文件段成可执行代码
根据重定位表进行修正
收集符号表信息
.symtab Section
.rel.text Section
.data Section
.text Section
使用objdump读取重定位表
使用readelf读取符号表
《程序员的自我修养——链接、装载和库》
Wine项目和WSL
Windows下的PE文件格式
Linux下的ELF文件格式
链接器的作用
ELF文件格式
链接器将多个目标文件和函数库链接成可执行文件
汇编器将汇编代码转换成机器码
编译器编译成汇编代码
课后思考
推荐阅读
总结延伸
ELF格式和链接
编译、链接和装载
为什么程序无法同时在Linux和Windows下运行?

该思维导图由 AI 生成,仅供参考

过去的三节,你和我一起通过一些简单的代码,看到了我们写的程序,是怎么变成一条条计算机指令的;if…else 这样的条件跳转是怎么样执行的;for/while 这样的循环是怎么执行的;函数间的相互调用是怎么发生的。
我记得以前,我自己在了解完这些知识之后,产生了一个非常大的疑问。那就是,既然我们的程序最终都被变成了一条条机器码去执行,那为什么同一个程序,在同一台计算机上,在 Linux 下可以运行,而在 Windows 下却不行呢?反过来,Windows 上的程序在 Linux 上也是一样不能执行的。可是我们的 CPU 并没有换掉,它应该可以识别同样的指令呀?
如果你和我有同样的疑问,那这一节,我们就一起来解开。

编译、链接和装载:拆解程序执行

第 5 节我们说过,写好的 C 语言代码,可以通过编译器编译成汇编代码,然后汇编代码再通过汇编器变成 CPU 可以理解的机器码,于是 CPU 就可以执行这些机器码了。你现在对这个过程应该不陌生了,但是这个描述把过程大大简化了。下面,我们一起具体来看,C 语言程序是如何变成一个可执行程序的。
不知道你注意到没有,过去几节,我们通过 gcc 生成的文件和 objdump 获取到的汇编指令都有些小小的问题。我们先把前面的 add 函数示例,拆分成两个文件 add_lib.c 和 link_example.c。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入分析了C语言程序在Linux和Windows下无法通用的原因。首先介绍了C语言代码编译、链接和装载的过程,以及生成可执行文件的方法。通过实例演示了编译、链接和装载的过程,揭示了程序在不同操作系统下无法通用的原因。文章指出,不同操作系统对可执行文件的格式和加载方式不同,导致同一程序无法在不同操作系统上执行。此外,还介绍了Linux下的ELF文件格式和Windows下的PE文件格式,以及通过兼容PE格式的装载器在Linux下运行Windows程序的可能性。最后,推荐了深入了解程序链接过程和ELF格式的阅读材料,并提出了课后思考的问题。整体而言,本文对程序在不同操作系统下无法通用的原因进行了深入浅出的解释,对读者快速了解程序跨平台运行问题具有重要参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入浅出计算机组成原理》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(64)

  • 最新
  • 精选
  • 老师,我曾经在linux上使用过wine,有好多window软件不能很好兼容的运行,这是为什么呢?是不是除了执行文件格式之外,还有其他的因素影响软件的运行呢?

    作者回复: 一步同学你好,当然,因为很多程序还依赖各种操作系统本身提供的动态链接库,系统调用等等。需要wine提供对应的实现,兼容格式只是万里长征第一步。

    2019-05-13
    2
    67
  • 有米
    Java的跨平台运行是如何做到的呢?跟本节内容有关系吗?

    作者回复: Java是通过实现不同平台上的虚拟机,然后即时翻译javac生成的中间代码来做到跨平台的。跨平台的工作被虚拟机开发人员来解决了

    2019-05-13
    57
  • 二星球
    老师好,就是没有操作系统,直接在硬件上运行的可执行程序,其格式应该不是pe或elf,应该是纯的机器指令吧,pe或elf格式的可执行程序是跟操作系统绑定的,经过翻译后成为纯机器指令,才能被执行,不知道这样理解对不。

    作者回复: 可以这样理解。实际机器启动加电的时候是从BIOS去读取MBR,再加载操作系统等等。 PE和ELF是在操作系统加载之后的事情了。

    2019-05-18
    4
    31
  • 二星球
    老师好,我有个问题,就是我可以用编程语言写一个不依赖操作系统的可执行程序,这个可执行程序不是pe格式,也不是elf的,那为什能执行呢,是不是因为这个可执行程序全是纯的cpu指令,没有其他要解析的东西?

    作者回复: 如果不是pe格式也不是elf格式,就不能执行啊。能执行是因为实际执行的不是你的程序。比如你写了一段python代码,实际执行的是python解释器,而不是你的py代码

    2019-05-13
    2
    28
  • 陆离
    高级语言都是先编译成汇编语言,再汇编成机器码执行的吗?

    作者回复: 如果是编译型的语言都是这样的。 也有通过解释器,或者虚拟机,转换成实际的机器码指令执行的。

    2019-05-23
    24
  • Spring
    补充一下: ELF其实是一种文件格式的标准,ELF文件有三类:可重定向文件、可执行文件、共享目标文件。代码经过预处理、编译、汇编后形成可重定向文件,可重定向文件经过链接后生成可执行文件。 另外我想请教一下,机器码是在哪一步形成的?

    作者回复: 简单地说,可以认为是在汇编之后变成了机器码放在了elf的代码段里。

    2019-05-13
    22
  • 有铭
    所以理论上,只要不涉及到windows和linux的系统api调用,理论上只要搞定了可执行文件格式这个问题,那么C程序就是二进制可移植的?

    作者回复: 除了系统调用,还要考虑是否有动态链接库的依赖等等

    2019-05-13
    16
  • 被过去推开
    Java的类加载是由jvm完成,大致过程为装载-链接-初始化-运行,所以是jvm帮我们屏蔽了操作系统之间的差异。为了加快程序启动速度,一些类会延迟加载,所以jvm中有很多动态链接。

    作者回复: 👍

    2019-08-12
    2
    14
  • kdb_reboot
    这里(gcc -g -c add_lib.c link_example.c)需要extern int addd(int a, int b);

    作者回复: 没错,不过其实你不加入对应的申明编译和运行也是能执行的,但是会有编译器的告警。

    2019-05-26
    8
  • 曾经瘦过
    mark 后面去读一读 程序员的自我修养

    作者回复: 👍这本书对于做系统开发的同学是必读书目之一。

    2019-05-13
    3
    7
收起评论
显示
设置
留言
64
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部