似乎我所参加的每个课程都是对新主题的介绍,该主题无法提供全面的知识,使我能够生成可以在IDE外部执行的实际程序。实现我不知道的事情既令人沮丧又令人生畏,令我感到困惑的是,一个经过认证的计算机科学课程可以提供一个课程,从一开始就不会对这个过程有所了解。
实际问题:原谅引言,但它提供了我(经验)的良好指示。我目前正在计算机架构课程中学习MIPS,并且已经获得了快速的装配介绍。程序执行方式的精细细节通常被描述为魔术,并在地毯下刷,以供另一位老师解释,如果可能的话。
据我所知,处理器电路在芯片之间变化很大,因此可能需要不同的低级指令来执行相同的高级代码。在成为原始机器代码之前,所有程序最终都转换为汇编语言,还是不再需要这一步骤?
如果是这样,处理器在什么时候开始执行自己独特的指令集?这是最低级别的代码,所以在这一点上程序指令是由处理器一点一点地执行的吗?
最后,所有架构都需要汇编语言吗?
答案 0 :(得分:10)
许多现代语言,例如Java和C#被编译成所谓的字节码。这是CPU不直接执行的代码,而是一种中间形式,可以在程序执行时及时编译为机器代码(JIT-ted)。在这种情况下,会生成依赖于CPU的机器代码,但通常不会通过人工可读的汇编代码。
答案 1 :(得分:4)
汇编语言只是原始机器代码的人类可读的文本表示。它的存在是为了(人类)程序员的利益。作为生成机器代码的中间步骤,它根本不是必需的。有些编译器会生成程序集,然后调用汇编程序将其转换为机器代码。但是,由于省略该步骤会导致更快的编译(并且不那么难),编译器(广义上讲)将倾向于直接生成机器代码。尽管如此,可以选择编译到程序集,以检查结果。
对于您的上一个问题,汇编语言是人类的便利,因此没有任何架构真正需要它。如果你真的想要,你可以创建一个没有的架构。但实际上,所有架构都有汇编语言。首先,创建一个新的汇编语言非常容易:为所有机器操作码和寄存器提供文本名称,添加一些语法来表示不同的寻址模式,而且您已经完成了大部分工作。即使所有代码都直接从高级语言转换为机器语言,如果只是在寻找编译器错误等时将其作为一种反汇编和可视化机器代码的方式,你仍然需要汇编语言。
答案 2 :(得分:2)
每个通用CPU都有自己的指令集。也就是说,某些字节序列在执行时对寄存器和存储器具有众所周知的记录效应。汇编语言是写下这些指令的便捷方式,因此人们可以读取和写入它们并理解它们的作用,而无需一直查找命令。可以相当安全地说,对于每个现代 CPU,都存在汇编语言。
现在,关于程序是否转换为程序集。我们首先要说CPU 不执行汇编代码。它执行机器代码,但是机器代码命令和装配线之间存在一对一的对应关系。只要你记住这个区别,就可以说像"现在CPU执行一个MOV,然后一个ADD"等等。当然,CPU执行与MOV命令相对应的机器代码。
也就是说,如果您的语言编译为本机代码,那么您的程序确实会在执行之前转换为机器代码。一些编译器(不是全部)通过发出汇编源并让汇编器完成最后一步来做到这一点。当存在时,该步骤通常被很好地隐藏。汇编表示仅在编译过程中短暂存在,除非您告诉编译器保持其完整。
其他编译器不使用装配步骤,但如果要求则发出装配。例如,Microsoft C ++采用选项/ FA - emit汇编列表以及目标文件。
如果它是解释性语言,则没有明确转换为机器。源代码行由语言解释器执行。面向字节码的语言(Java,Visual Basic)介于两者之间;它们被编译为与机器代码不同的代码,但比高级源更容易解释。对于那些人来说,他们没有转换为机器代码也是公平的。
答案 3 :(得分:0)
基本上是的,Java的程序集称为字节码,任何芯片的微体系结构都有ISA,它由汇编指令或类似的东西组成,而同一个ISA可以在许多不同的芯片上实现。如果您学习MIPS是一个很好的介绍,那么您可以了解编译器如何将C转换为MIPS。然后,您可以看到MIPS指令如何转换为机器代码,并且机器代码将具有将执行指令的ALU的操作码。有关更多信息,您可以阅读Hennessy / Patterson,他们在计算机硬件上写了两本好书:“Computer Organization & Design”和“计算机体系结构 - 定量方法”
答案 4 :(得分:0)
生成本机机器代码的编译器会生成适当的汇编语言,然后汇编成机器代码。这通常只需一步完成,但是一些编译器(如GCC)也可以输出中间组件。
你是对的,不同的架构有不同的指令集。利用这些差异是编译器如何为一个或另一个处理器优化可执行文件。
答案 5 :(得分:0)
这是一个相当大的兔子洞,你往下看。
话虽如此,不,并非所有程序都变成汇编语言。如果我们排除即时编译,解释语言喜欢ruby,lisp和python,以及在java和c#等虚拟机(VM)上运行的程序不会转换为程序集。相反,它们是一个现有程序,一个解释器或虚拟机,它接收源(解释)或字节码(VM)(不是您计算机的汇编语言)并运行它们。当解释器看到特定的输入序列并采取正确的操作时,即使之前没有看到该特定输入,解释器也知道该做什么。
编译程序,就像你用C或C ++编写的那样,作为编译过程的一部分,可以变成汇编语言,然后变成机器语言。通常会跳过此步骤以加快速度。一些编译器(如LLVM)输出一个通用的bitcode,因此他们可以将生成bitcode的编译器部分从将bitcode转换为机器代码的部分中分离出来,从而允许跨架构重用。
然而,即使操作系统将CPU视为消耗机器代码的东西,许多CPU也会使用较低级别的微代码。指令集中的每个指令(可指定级别)由CPU实现,作为更简单的微代码操作的序列。在CPU之间,指令集可以保持不变,而实现指令的微代码会发生变化。将指令集视为CPU的API。
答案 6 :(得分:0)
所有处理器都在位上操作,我们称之为机器代码,由于各种原因它可以采用非常不同的口味,为保护想法的专利构建更好的鼠标陷阱。从用户的角度来看,每个处理器都使用某种机器代码,有些内部将其转换为微代码,另一种机器代码,而其他处理器则不然。当你听到x86 vs arm vs mips vs power pc时,这不仅仅是公司名称,而且它们各自的处理器也有自己的指令集,机器代码。 x86指令集虽然演变仍然与他们的历史相似,但您可以轻松地从其他人那里挑选x86代码。对所有公司来说都是如此,你可以看到mips遗留下来的mips和手臂,等等。
因此,要在某个时刻在处理器上运行程序,必须将其转换为该处理器的机器代码,然后处理器才能处理它。各种语言和工具以各种方式完成。编译器不需要从高级语言编译为汇编语言,但它很方便。首先,你基本上需要一个处理器用于该处理器,所以工具就在那里。通过查看人类可读的汇编语言而不是机器代码的位和字节,可以更容易地调试编译器。一些编译器,如JAVA,python,旧的pascal编译器都有一个通用的机器代码(每种语言都有自己不同的编译器),在x86上的java和arm上的java对那一点做同样的事情是通用的,然后那里是一个特定于目标的(x86,arm,mips)解释器,它解码通用字节码并在本机处理器上执行它。但最终它必须是运行它的处理器的机器代码。
这些编译层的方法也有一些历史,我认为它是有点unix构建块的方法,让一个块做前端而另一个块后端并输出asm然后asm到对象是自己的工具和与他人联系的对象是它自己的工具。每个块都可以包含和开发,具有受控的输入和输出,有时可以替换为适合同一位置的另一个块。编译器类教授此模型,因此您将看到使用新编译器和新语言进行复制。解析前端,高级语言的文本。进入中间编译器特定的二进制代码,然后在后端获取内部代码并将其转换为目标处理器的程序集,例如允许gcc和许多其他代码更改后端,以便前端和中间可以重用于不同的目标。然后分别有一个汇编程序,还有一个单独的链接器,它们本身就是独立的工具。
人们不断尝试重新发明键盘和鼠标,但即使新发明更好,人们仍然对他们坚持使用它的旧方式足够舒服。对于编译器和操作系统以及许多其他事情也是如此,我们依赖于我们所知道的以及他们经常编译为汇编语言的编译器。
答案 7 :(得分:-1)
以下是一些令您困惑的事情: