我正在查找pypy项目(Python中的Python),并开始思考是什么在运行python的外层?当然,我猜想,这不可能像俗话所说的“乌龟一路倒下”!毕竟,python不是有效的x86程序集!
很快我就想起了bootstrapping的概念,并查阅了编译器bootstrapping。“好吧,”我想,“所以它既可以用不同的语言编写,也可以用汇编语言手工编译”。为了提高性能,我确信C编译器是从汇编中构建出来的。
这一切都很好,但问题仍然存在,计算机如何获得该程序集文件?!
假设我买了一个新的cpu,上面什么都没有。在第一个操作中,我希望安装一个运行C的操作系统。什么运行C编译器?BIOS中是否有微型C编译器?
有人能给我解释一下吗?
发布于 2011-06-21 06:58:55
说我买了一台新的cpu,上面什么都没有。在第一个操作中,我希望安装一个运行C的操作系统。什么运行C编译器?BIOS中是否有微型C编译器?
我明白你在问什么。如果我们没有C编译器,必须从头开始,会发生什么?
答案是你必须从组装或硬件开始。也就是说,您可以在软件或硬件中构建编译器。如果世界上没有编译器,现在你可能可以用汇编语言更快地完成它;然而,在过去,我相信编译器实际上是专用的硬件。wikipedia article有点短,在这一点上不支持我,但没关系。
我猜下一个问题是今天会发生什么?这些编译器编写人员多年来一直在忙于编写可移植的C语言,所以编译器应该能够自行编译。在很高的层次上,什么是编译是值得讨论的。基本上,您可以获取一组语句并从它们生成程序集。就这样。实际上,这要复杂得多-你可以用词法分析器和解析器做各种各样的事情,我只理解其中的一小部分,但本质上,你正在寻找将C语言映射到汇编。
在正常操作下,编译器会生成与您的平台相匹配的汇编代码,但它并不需要这样做。它可以为你喜欢的任何平台生成汇编代码,只要它知道怎么做。因此,让C在你的平台上工作的第一步是在现有的编译器中创建一个目标,开始添加指令并使基本代码工作。
一旦这样做了,理论上,你现在可以从一个平台交叉编译到另一个平台。下一个阶段是:为该平台构建内核、引导加载程序和一些基本的用户端实用程序。
然后,您可以开始为该平台编译编译器(一旦您有了运行构建过程所需的一切工作用户空间)。如果成功,您就拥有了基本的实用程序、工作内核、用户空间和编译器系统。您现在可以顺利上路了。
请注意,在移植编译器的过程中,您可能还需要为该平台编写汇编器和链接器。为了保持描述简单,我省略了它们。
如果您对此感兴趣,那么Linux from Scratch是一个有趣的读物。它没有告诉你如何从头开始创建一个新的目标(这是非常重要的)-它假设你要为一个现有的已知目标构建,但它确实向你展示了如何交叉编译要点并开始构建系统。
Python实际上并不是汇编成汇编的。首先,正在运行的python程序会跟踪对对象的引用计数,这是cpu不能为您完成的。然而,基于指令的代码的概念也是Python的核心。试试这个:
>>> def hello(x, y, z, q):
... print "Hello, world"
... q()
... return x+y+z
...
>>> import dis
dis.dis(hello)
2 0 LOAD_CONST 1 ('Hello, world')
3 PRINT_ITEM
4 PRINT_NEWLINE
3 5 LOAD_FAST 3 (q)
8 CALL_FUNCTION 0
11 POP_TOP
4 12 LOAD_FAST 0 (x)
15 LOAD_FAST 1 (y)
18 BINARY_ADD
19 LOAD_FAST 2 (z)
22 BINARY_ADD
23 RETURN_VALUE在那里,您可以看到Python对您输入的代码的看法。这是python字节码,即python的汇编语言。它实际上有自己的“指令集”,如果你喜欢实现语言的话。这就是虚拟机的概念。
Java也有同样的想法。我获取了一个类函数,并运行javap -c class来获取以下内容:
invalid.site.ningefingers.main:();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_0
3: istore_1
4: iload_1
5: aload_0
6: arraylength
7: if_icmpge 57
10: getstatic #2;
13: new #3;
16: dup
17: invokespecial #4;
20: ldc #5;
22: invokevirtual #6;
25: iload_1
26: invokevirtual #7;
//.......
}我想你已经明白了。这些是python和java世界的汇编语言,也就是python解释器和java编译器分别是如何思考的。
其他值得一读的是JonesForth。这既是一个工作中的forth解释器,也是一个教程,对于思考“事情是如何执行的”以及如何编写一种简单、轻量级的语言来说,我推荐它是不够的。
发布于 2011-06-21 06:36:51
为了提高性能,我确信C编译器是从汇编中构建出来的。
如今,C编译器(几乎?)完全用C(或更高级的语言--例如Clang就是C++ )编写。编译器从包含手工编写的汇编代码中获益很少,甚至一无所获。需要花费大部分时间的东西都很慢,因为它们解决了非常困难的问题,其中“困难”意味着“巨大的计算复杂性”-在汇编中重写最多带来持续的加速,但在那个级别上这些都不再重要了。
此外,大多数编译器都希望具有高可移植性,因此在前端和中间端使用特定于体系结构的技巧是不可能的(而在后端,它们也是不可取的,因为它们可能会破坏交叉编译)。
说我买了一台新的cpu,上面什么都没有。在第一个操作中,我希望安装一个运行C的操作系统。什么运行C编译器?BIOS中是否有微型C编译器?
当你安装一个操作系统时,(通常)没有运行C编译器。安装CD中包含了该体系结构的易于编译的二进制文件。如果包含C编译器(就像许多Linux发行版一样),那么它也是一个已经编译好的可执行文件。而那些让你构建自己的内核的发行版也至少包含一个可执行文件--编译器。当然,除非您必须使用C编译器在任何现有安装上编译您自己的内核。
如果您所说的“新CPU”指的是不能向后兼容任何尚未支持的新体系结构,那么自托管编译器可以遵循通常的移植过程:首先为新目标编写后端,然后针对它进行编译,然后突然之间您就得到了一个成熟的编译器,它在新平台上具有久经沙场(编译了整个编译器)的本机后端。
发布于 2011-06-21 06:36:22
如果你购买了一台预装了操作系统的新机器,它甚至不需要在任何地方包含编译器,因为所有的可执行代码都是由提供操作系统的人在其他机器上编译的--你的机器不需要自己编译任何东西。
如果你有一个全新的CPU架构,你是如何做到这一点的?在这种情况下,您可能会首先为您的新CPU架构(“目标”)编写一个新的代码生成后端,用于运行在其他平台(“主机”)上的现有C编译器-- cross-compiler。
一旦你的交叉编译器(在主机上运行)足够好地生成一个正确的编译器(和必要的库,等等)这将在目标上运行,然后您可以在目标平台上编译编译器本身,并最终得到目标本机编译器,该编译器在目标上运行并生成在目标上运行的代码。
对于一种新的语言,这也是同样的原则:你必须用一种你有工具链的现有语言编写代码,它会将你的新语言编译成你可以使用的东西(让我们称之为“引导编译器”)。一旦你做的足够好,你就可以用你的新语言编写一个编译器(“真正的编译器”),然后用bootstrap编译器编译真正的编译器。在这一点上,您正在用新语言本身编写新语言的编译器,并且您的语言被称为“自托管”。
https://stackoverflow.com/questions/6418199
复制相似问题