实现和语法之间的区别



经过大量的研究,我想我开始学习汇编程序是如何工作的

汇编程序的工作方式类似于为预期体系结构编译代码的编译器。 而汇编语言是一个通用的想法,以不同的方式实现。 但我不明白语法是如何工作的? 不就是实施吗?

我已经搜索过,但我找不到任何解释语法如何工作以及它与实现有何不同的东西。

我看过 http://sun.hasenbraten.de/vasm/中使用的语法这个词,有多少汇编语言还有很多文章。

但我仍然不明白。大多数情况下,我发现东西生活 AT&T 语法与英特尔语法(有人可以解释吗?

这也是一个值得问的问题:汇编程序是否有可能支持多种架构?如果是,如何?

我认为您试图使这过于复杂。

因此,虽然许多人可以处理这个问题,并根据需要以这种方式编写和编程:

0xe0821003
0xe0021003
0xe0421003

只是写下一点。 这很乏味,会增加错误,增加错误的几率。 不容易阅读,所以不是很易于维护。

因此,对于该指令集(ISA)的那些位,IP或处理器供应商创建了一种以人类可读/可写/可维护的方式传达预期内容的方法。

那将是

add r1,r2,r3
and r1,r2,r3
sub r1,r2,r3

但这是针对该特定目标,并使用发明人提供的推荐语言。 真正重要的是机器代码。 我们中的任何一个人都可以创建一个汇编语言来接受这个

bob b,c,d
ted b,c,d
joe b,c,d

这导致每个汇编语言的机器代码相同。 我已经看到,创建和使用了支持此功能的工具

r1 = r2 + r3
r1 = r2 & r3
r1 = r2 - r3

作为一种汇编语言(我正在考虑的目标的机器代码实际上使它更容易编写/使用)。 我们可以很容易地制作一个汇编程序,它采用该语法并创建与上面相同的机器代码。 没有什么能阻止我们这样做。 或者,即使将这样的语法添加到支持 add r1,r2,r3 的现有汇编器中,也可以由同一工具支持。

重要的是机器代码,我们不能简单地编造我们想要的任何位,并让已经通过一组规则实现的目标处理器更改这些规则(除非处理器被设计成像 fpga 一样做到这一点,但你知道这不是我在说的)。

对此存在严重的误解,伙计们认为x86是唯一具有不同语法的语法,并且每个目标都是一个语法。 那里的故事是英特尔与AT&T,英特尔定义并创建了支持这一点的工具:

mov ah,05h

对于我们很多人来说,左边的目的地是非常自然的,因为我们上过的每堂数学课都使用了这个惯例。

add r1,r2,r3
r1 = r2 + r3

但是那些为x86迅速进入的非DOS平台创建不同汇编程序的人(其他一些操作系统,但一般嵌入)。 也许是因为他们喜欢最后看到目的地,他们宁愿看到

mov 05h,al

除了看起来很傻之外,这没有什么错

add r2,r3,r1
r2 + r3 = r1

制作您想要的任何语法都是完全合法的,只要......你知道这个...您构建正确的机器代码。

没有像一些高级编程语言那样的管理机构。 充其量你有一个工具链问题,你有一个链接器、汇编器和编译器,编译器的输出通常是汇编语言,汇编器将其变成链接器变成二进制的对象,因此称为工具链。
编译器的输出和汇编器的输入必须达成一致,通常一方发号施令,另一方服从。 因此,如果由于某种原因您想滑入不同的后端,那么您需要一个符合 copmiler 输出的后端。 汇编器和链接器之间的情况完全相同,文件格式是完全任意的,无论作者选择发明什么,只要它能完成工作,但是对于一个工具移交给另一个工具,必须有一个商定的格式和/或另一个工具从 on 格式转换为另一个格式。

因此,像 gnu gcc 这样单独开发的编译器希望符合像 gnu 这样单独开发的汇编程序。 这将是最接近于一个规定语言规则的管理机构。作为开源,个人可以随意向一个功能添加一个功能,并在另一个功能中实现该功能的使用。

回到AT&T与英特尔。 这被错误地视为汇编语言差异的唯一情况。

去尝试组装这个完全合法的手臂代码

add r1,r2,r3 ; and r1,r2,r3
add r1,r2,r3 @ and r1,r2,r3

至少一个工具是快乐的,而另一个工具不是,可以采取一条线

add r1,r2,r3 ; and r1,r2,r3

并且至少有一个工具可以提供

0xe0821003
0xe0021003

至少另一个将其作为输出

0xe0821003

(以某种对象文件格式包装,这些位以该格式表示)

关键是语言的每个细微差别都是相关的,有些标签必须从第一列开始并带有冒号,有些则没有。 有些指令必须以点开头。GLOBAL 和其他人不是 GLOBAL,就在那里,代码完全不兼容,没有进入实际指令。 然后你有指令差异。 有一种非常糟糕的新时尚,不使用寄存器名称,我受不了,所以我可能无法正确理解它们

add a0,v1,v2

这当然会导致完全不兼容,以及这种疯狂:

mov %eax,0

几十年成功的解析器,你变得懒惰?

现在我们不知道你所说的实施是什么意思。 理想情况下,设计良好的汇编语言是可以采用汇编语言"指令"并映射到特定机器指令的语言。 但不幸的是,我们有一些模糊的汇编语言和/或模糊的指令集。

例如,在我刚刚编造的指令集和汇编语言中,您可能支持

add r0,r1,#0
mov r0,r1

出于某种原因,实际上为这些实现了不同的指令。 通常你会看到后者只是前者的伪代码,但我们在汇编语言和x86的指令集中都看到,有很多地方你可以用多种方式"实现"程序员的意图。

这就是你所说的实施吗?

更干净,更精简的指令集将保留指令集空间,而不是那些,例如,有些可能没有nop,相反,工具可能只是使用

and r0,r0

虽然如果他们这样做意味着他们也可以使用

and r1,r1

相反。 创建一个可以以不同方式实现的汇编语言指令。 您还将看到伪指令。

push {r1}

这成为

stmia r13!,{r1}

因为指令集实际上没有推送指令。

汇编已经演变成,曾经是十六进制数字,对于某些语言来说,十六进制数字是这样的 12 美元,英特尔喜欢这个 12h,但后来 C 变得流行和主导,然后工具开始支持 0x12,所以你可以找到一个兼容的编译器家族,有一天他们不支持0x12和下一个版本他们支持。

ARM在成为橡子之后做了一些有趣的事情。 他们创建了一个向后兼容 16 位指令集 32 位指令集,在他们的文档中,他们向您展示了完全兼容的 32 位指令,与较短的指令相同(显然只能走单向)。

一种方法是大多数指令仅支持一半的寄存器 r0-r7 而不是所有寄存器 r0-r15,这意味着指令中只需要三位而不是四位。 arm有一些并不罕见的东西,但也不是常见的三个寄存器指令添加r1,r2,r3。许多较旧的指令集都可以添加 r1,r2,无论语法是什么,这意味着操作数也是目的地 r1=r1+r2。 他们这样做是为了一些拇指的指示。 为什么这与这个讨论相关,因为对于早期的拇指汇编者来说,这是

add r1,r1,r2 

是非法的,你会得到一个错误,即使在手臂上这是合法的。 然后后来工具开始支持它,因为意图被理解了,因为 arm 的目标是这种统一的语法,这简直是愚蠢的,它让事情变得更糟而不是更好,但无论如何......因此,有一天/版本,特定的汇编程序在用作拇指时不再抱怨该语法。

比规则臂更多的例外是现在有两个三个(很多)指令集,让我们使用特定的拇指和特定的臂,只要你停留在每个的子集中就可以用于不同的指令集(机器代码),

如上所述
add r1,r1,r3
and r1,r1,r3
sub r1,r1,r3
.thumb
add r1,r1,r3
and r1,r1,r3
sub r1,r1,r3

0: e0811003 添加 R1, R1, R3 4:E0011003 和 R1、R1、R3 8: E0411003 子 R1, R1, R3 C: 18C9 添加 R1, R1, R3 E: 4019 和 R1, R3 10: 1AC9 潜艇 R1, R1, R3

现在这里有一些 arm gnu 的细微差别,它们一直在沿着这个语法兔子洞 特定目标的汇编语言之间的差异,该目标的汇编语言(不是 x86)的汇编语言之间的差异不同。

一般来说,尝试制作具有不同目标的指令集是没有任何意义的,除了像上面这样的东西,你有一个从另一个派生的指令集,并且曾经或一段时间在同一内核中实现。 尝试制作一种为 x86 或 arm 制作机器代码的语法只是更改目标但使用相同的源。 这毫无意义,何必呢。 关键是制作机器代码,您希望完全控制生成的特定构造。 因此,您需要目标特定信息才能做到这一点。 如果你撤回并删除目标特定细节,那么它就不再是汇编语言,它是一种高级语言,如 C 或 python 或 JAVA 或其他语言。 这就是为什么我们拥有那些高级语言的原因,这就是 C 在 60 年代出现的地方来解决这个确切的问题,试图实现 darpanet,但使用不兼容的处理器来成为我们今天可能称之为调制解调器和/或路由器的东西。 由于世界处于快速处理器开发中,您必须不断在汇编中重写相同的程序和/或需要创建高级语言,然后在重新定位编译器后重新定位它们,然后理想情况下,您可以在新目标上重用一定比例的"应用程序"。

现在有一些汇编语言在一些圈子里很流行,这些语言是库存汇编让我制作我想要的机器代码的组合,还有一些更高级的功能来节省打字。

语法的工作原理是创建一种可以传达想法或思想的语言。 如果我画一个盒子,上面有一个三角形,上面有另一个矩形,上面有一些摆动的线,四分之一圆,光线从纸的角落出来,两条垂直线,上面有一些圆形的线条,我们都同意,无论我们的母语是什么,房子的角落里有太阳,旁边有一棵树。

成功的语法是有意义且有用的语法,它并不比机器代码本身更难。

实现只是简单地解析该语法并制作机器代码或数据,或者在链接期间第二次传递或使用标签来计算部分指令。 在这里,成功的语法是允许我们正确描述我们希望工具生成的机器代码,在功能上肯定且理想情况下具体。

最新更新