第一个计算机程序是如何创建的?
可能的重复:
第一个编译器是如何编写的?
这个问题一直困扰着我。 编译一个程序需要编译器,编译器也是程序的一种,那么什么编译器编译呢? 有人告诉我,第一个编译器是用汇编代码或机器代码编写的。 但仔细想想,这还不是完整的故事。毕竟,在没有操作系统和驱动程序的情况下,机器代码如何从硬盘驱动器到 RAM 再到 CPU?驱动程序必须以某种方式进行编程。
我知道最早期的计算机有开关,可以通过拨动开关来指示位。我想知道如何实现从开关到让 CPU 读取机器代码而不需要计算机程序告诉它这样做的方式的飞跃。
Possible Duplicate:
How was the first compiler written?
This question has always been bothering me.
To compile a program, you need a compiler, which is also a type of program, so what compiled the compiler?
Somebody told me that the first compilers were written in assembly or machine code.
But thinking about that, that is still not the complete story. After all, how does the machine code go from the hard drive to RAM to the CPU without an operating system and drivers? The drivers had to have been programmed somehow.
I know that the very early computers had switches and allowed you to flip the switch to indicate bits. I am wondering how the leap was made from switches to a way to get the CPU to read machine code without needing a computer program to tell it to do so.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
简而言之:第一个程序是用原始机器代码精心编写的,一切都是从那里构建的。
这个想法被称为引导。假设您有一台带有处理器、一些闪存和硬盘的裸机。通常,处理器在加电时配置为从非易失性存储器(例如 CMOS 或闪存)中的固定位置加载称为引导加载程序的简单操作系统。这个操作系统非常简单,并且具有足够的功能来将计算机指向真正操作系统所在的磁盘位置。然后这个操作系统可以打开越来越多的设备并加载越来越复杂的程序,直到最终整个操作系统启动并运行。
但是这个bootloader是用什么写的呢?最初,这些是用原始机器代码编写并硬编码到机器中的。它将运行的程序也将用机器代码编写,这将是令人难以置信的缓慢和乏味的工作。最终,有人用机器代码编写了第一个简单的汇编程序。一旦有了这个汇编程序,您就可以开始用汇编语言编写程序,包括汇编程序本身。事实上,一旦你有了一个简单的汇编程序,你就再也不需要编写机器代码了。你可以继续用汇编语言编写汇编程序!
从这一点开始,您可以通过首先使用现有工具(例如汇编器)编写编译器来构建更复杂的编程语言,以获得足够的可用功能,以便编译器可以进行基本编程。然后,您使用该编译器为编程语言本身编写一个编译器,并使用相同的技巧在您之前的工作基础上进行构建,以获得更大、更酷的东西。这种技术至今仍在使用——大多数编译器都是用它们编译的语言编写的。
总而言之,在过去的某个糟糕时刻,一切都必须手工完成,但由于那些这样做的人们的辛勤工作,我们可以在已有的基础上进行构建。
The short answer: the first programs were meticulously written in raw machine code, and everything was built up from there.
The idea is called bootstrapping. Suppose that you have a bare machine with a processor, some flash memory, and a hard disk. Typically, the processor is configured on power-up to load a simple operating system called the bootloader from a fixed location in non-volatile memory (for example, CMOS or flash). This OS is extraordinarily simple and has just enough functionality to point the computer to the spot on disk where the real OS lives. This OS can then turn on more and more devices and load more and more complicated programs, until eventually the whole OS is up and running.
But what is this bootloader written in? Originally, these were written in raw machine code and hardcoded into the machine. The programs it would run would be written in machine code as well, which would be unbelievably slow and tedious to work with. Eventually, someone wrote the first simple assembler in machine code. Once you have this assembler, you can start writing programs in assembly, including the assembler itself. In fact, once you have a simple assembler, you never need to write machine code again. You can just keep writing the assembler in assembly!
From this point you can build more complex programming languages by first writing the compiler using existing tools (the assembler, for example) to get just enough functionality available so that the compiler can do basic programming. You then use that compiler to write a compiler for the programming language itself, and use the same trick to build off of your previous work to get something bigger and cooler. This technique is still used today - most compilers are written in the language they compile to.
To summarize, everything had to be done by hand at some awful point in the past, but thanks to the hard work of the people who did this we can build off of what's already there.
在微型计算机行业的早期,您必须直接使用拨动开关费力地输入机器代码。一个典型的例子是 Altair 8800(如下所示,但可能是复制品):
这样,您可以设置地址和/或数据位的二进制开关,然后使用命令切换开关之一要么:
Altair 在
RESET
后将当前地址设置为零,因为这是 CPU 开始执行代码的位置,所以这通常就足够了。否则,您可以设置地址开关并切换EXAMINE
将当前地址设置为其他地址。如果您错误地输入了程序并需要对其进行修补(而不是从头开始重新进行),则也需要进行地址选择过程。一旦地址符合您的要求(
EXAMINE
将在地址 LED 上显示该地址以及数据 LED 上的当前内容),您将切换数据开关并执行DEPOSIT
将该数据放入当前地址(DEPOSIT-NEXT
相同,但它在存款之前首先递增当前地址,这对于顺序输入很有用)。整个过程可以在 这个,基本思想是:
EXAMINE/DEPOSIT/DEPOSIT-NEXT
流程将每个字节输入内存,非常小心LED正确指示您刚刚存入的字节。第二个要点可能是最难的一点,因为您需要调整跳转到可能尚未组装的指令,因此您基本上是一个缓慢的、生物的、多遍汇编器。
例如,请考虑以下(非常简单)8080 代码,该代码是从在线资源中收集的:
请注意,这些数据字节
c3 00 00
是十六进制,但人们经常使用八进制,因为 Altair 开关分为三个而不是三个四个;这将给出303 000 000
。因此,对于该特定程序,您可以:
RESET
,将当前地址设置为零。303
(JMP
操作码)的二进制数据开关101 000 101
。DEPOSIT
开关,将该字节放入内存位置0,并在LED上显示该地址和存储的数据以供检查。000
的二进制数据开关000 000 000
,即要跳转到的地址的第一个字节。DEPOSIT-NEXT
开关,将当前地址前进到1,将字节存入该地址,并再次在LED上显示地址和数据。DEPOSIT-NEXT
开关,将当前地址前进到2,将字节存入该地址,并再次在LED上显示地址和数据。无需更改数据开关,因为它们与前一个字节相同。此时,程序已在内存中,您可以切换
RESET
然后RUN
以查看其运行情况。不过,如果您想看到 LED 在运行时发生变化,您可能会连续切换SINGLE-STEP
。另一件需要记住的事情是,不要求程序必须在其预期运行的平台上编写。在另一个平台上运行的交叉汇编器(或编译器)可以用来绕过上述费力的手工组装过程。
您仍然必须将字节输入目标平台,但也有解决方案。纸带阅读器可以添加到 Altair 中,这样,只要交叉汇编器系统可以生成磁带,就只需要一个小型加载程序来加载和运行它。
例如,在早期的嵌入式时代(在“嵌入式”意味着巨大的 Linux 盒子之前),我是为基于 6809 的设备开发操作系统、驱动程序和应用程序代码的团队的一员。实际的开发工具都托管在早期的 UNIX 系统上,并且这些工具被烧录到 EPROMS 上以插入设备中。这些设备根本没有进行任何开发,因为它们非常是针对其一项实际任务量身定制的。
In the early days of the microcomputer industry, you had to laboriously enter machine code directly using toggle switches. A classic example is the Altair 8800 (shown below though possibly a replica):
With this, you would set the binary switches for the address and/or data bits, then use one of the command toggle switches to either:
The Altair, after
RESET
, had the current address set to zero and, since this is where the CPU will start executing code, that was usually sufficient. Otherwise, you could set the address switches and toggleEXAMINE
to set the current address to something else. That address selection process was also needed in the case where you had entered your program incorrectly and needed to patch it (rather than doing it all again from scratch).Once the address was what you wanted (
EXAMINE
would show it on the address LEDs along with the current content on the data LEDs), you would toggle the data switches and doDEPOSIT
to put that data into the current address (DEPOSIT-NEXT
was identical but it first incremented the current address before depositing, useful for sequential entry).The whole process can be found on sites like this one, with the basic idea being:
EXAMINE/DEPOSIT/DEPOSIT-NEXT
process to enter each byte into memory, being very careful that the LEDs correctly indicate the byte you just deposited.That second bullet point is probably the hardest bit since you need to adjust for jumping to instructions that may not have yet been assembled, so you're basically basically a slow, biological, multi-pass assembler.
For an example, consider the following (very simple) 8080 code, gleaned from online sources:
Note those data bytes
c3 00 00
are hexadecimal but people often used octal since the Altair switches were grouped into three rather than four; that would give303 000 000
.Hence, you would, for that specific program:
RESET
, giving a current address of zero.101 000 101
for octal303
, theJMP
opcode.DEPOSIT
switch, putting that byte into memory location 0, and showing that address and the deposited data on the LEDs for checking.000 000 000
for octal000
, the first byte of the address to jump to.DEPOSIT-NEXT
switch, advancing the current address to 1, depositing the byte in that address and again showing the address and data on the LEDs.DEPOSIT-NEXT
switch again, advancing the current address to 2, depositing the byte in that address and again showing the address and data on the LEDs. There was no need to change the data switches as they were identical to the previous byte.At that point, the program is in memory, and you can toggle
RESET
thenRUN
to see it in action. Though, if you wanted to see the LEDs change as it ran, you'd probably continuously toggleSINGLE-STEP
instead.The other thing to keep in mind is that there's no requirement that a program be written on the platform it's intended to run on. Cross-assemblers (or compilers) running on another platform can be used to bypass the laborious hand-assembling process described above.
You still have to get the bytes into the target platform but there were solutions for that as well. Paper tape readers could be added to Altair so, provided the cross-assembler system could produce the tapes, only a small loader program would be needed to load and run it.
For example, in the early embedded days (before "embedded" meant huge honkin' Linux boxes), I was part of a team developing operating system, drivers, and application code for a 6809-based device. The actual development tools were all hosted on an early UNIX system, and these were burnt onto EPROMS for insertion into the devices. No development at all took place on those devices, as they were very tailored toward their one real task.
曾几何时,使用计算机时,您需要输入二进制机器代码。人们厌倦了这样做,所以他们制作了一个可以读取汇编的程序(带有机器代码)。一段时间后,他们意识到用汇编语言编写很糟糕,因此他们使用汇编语言来编写高级语言,例如 FORTRAN。
要了解完整的故事,请进入大学并参加一些 CS 或 COMPE 课程。
Once upon a time to use a computer you entered machine code in binary. People got tired of doing that, so they made a program (with machine code) that would read assembly. After a while they realized that writing in assembly sucked, so they used assembly to make high level languages such as FORTRAN.
To get the full story, enroll in college and take some CS or COMPE classes.