第一遍和第二遍汇编程序的教程

时间:2012-02-09 11:43:25

标签: algorithm assembly

有没有很好的教程解释汇编程序的第一次和第二次传递及其算法?我搜索了很多关于他们但没有得到令人满意的结果。 如果有的话,请链接教程。

2 个答案:

答案 0 :(得分:3)

不知道任何教程,真的不是很多。

one:
  inc r0
  cmp r0,0
  jnz one
  call fun
  add r0,7
  jmp more_fun
fun:
  mov r1,r0
  ret
more_fun:

汇编程序/软件,就像人类一样,将从上到下读取源文件,文件中的字节0到最后。对于你在每次传球中所完成的内容,没有严格的规则,并且它不一定是文件中的传递文件"但是关于数据的传递"。

第一关:   当你阅读每一行时,你会解析它。您正在构建某种具有文件顺序指令的数据结构。当您遇到像一个标签的标签时,您会跟踪前面的指令,或者您可能在指令之间有标记,但是您选择实施它。当您遇到使用标签的指令时,您有两个选择,您现在可以去寻找那个标签,如果它是一个向后看的标签,那么您应该已经看过它就像jnz one指令一样。 IF 你到目前为止一直在跟踪数字和大小(如果是可变字长)指令,你现在可以选择编码这条指令,如果它是相对指令,如果指令集使用绝对你可能不管怎样,不得不留下一个占位符。

现在调用fun并跳转more_fun指令会产生问题,当你看到这些指令时你无法解决它们,你不知道这些标签是否属于这个文件或是在另一个文件中,所以你不能编码第一遍的这条指令,你必须保存以供日后使用,这就是第二次通过的原因。

第二遍可能是跨越您的数据结构而不是实际上在文件上,这是特定于实现的。例如,你可能有一个一维的结构数组,一切都在那里。例如,您可以选择对该数据进行多次传递,通过数组启动一个索引以查找未解析的标签。找到未解析的标签时,通过数组发送第二个索引以查找标签定义。如果您没有找到它,那么特定于应用程序,您的汇编程序是否创建了以后要链接的对象,或者它是否创建了二进制文件是否必须在此一个程序集中将所有内容解析为二进制步骤?如果对象然后您认为这是外部的,除非特定于应用程序,您的汇编程序需要将外部标签定义为外部标签。因此,缺少的标签是否是错误是特定于应用程序的。如果它不是错误,那么,特定于应用程序,您应编码最长/最远的分支类型,留下链接器要填写的地址或距离详细信息。

对于您发现的标签,您现在对于距离有多大概念。现在,根据汇编程序的指令集和/或功能,您需要对数据进行多次传递。你需要开始编码指令,假设你至少有一种相对距离调用或分支指令,你必须决定第一个编码通道是否希望我所假设的是一个更短/更小的指令相对距离分支或假设较大的分支。您无法确定较小的一个是否会到达,直到您通过指令获得一个或几个编码通道。

top:
  ...
  jmp down
  ...
  jnz top
  ...
down:

当您对jmp进行编码时,您可以乐观地选择将其编码为较小的(字节数/字,如果可变字长)相对分支,从而确定距离。当你到达jnz顶部时,让我们说它恰好是接近顶部的字节,使用相对分支进行编码。在第二遍,虽然你必须回去完成jmp,你发现它不会到达,你需要更多的字节/单词来编码它作为一个长分支。现在jnz top也必须成为一个远分支(导致再次移动)。你必须继续通过指令,计算他们的距离远/短,直到你通过没有变化。小心不要陷入无限循环,一个通过你缩短一个指令,但这导致另一个延长,在下一次通过时,延长一个导致另一个延长但第二个缩短,这将永远重复

我们可以回到顶部,在第一遍中,您可能会构建多个或多个数据结构,可能在您构建已找到标签的列表以及缺少标签的列表时。第二遍你浏览失踪列表,看看它们是否在找到,然后以这种方式解决它们。或者也许在第一次传递时,有些人可能会认为这是一个单通道汇编程序,当你找到一个标签时,在继续浏览文件之前,你回头看看是否有人正在寻找那个标签(或者如果那个标签已经被定义了)声明一个错误)我会称之为多遍汇编程序,因为它仍然会多次传递数据。

现在让它变得更糟。查看arm指令集作为示例和任何其他固定长度指令集。您的相对分支通常在一条指令中编码,因此固定长度的指令集。远分支通常涉及从该地址处找到的数据加载pc,这意味着您确实需要两个指令项,然后在该指令的相对范围内的某个位置包含分支的绝对地址的数据字。您可以选择强制用户创建这些,但是对于ARM汇编程序,他们可以并且将为您执行此操作,最简单的示例是:

ldr r0,=0x12345678
...
b somewhere

该语法意味着使用值0x12345678加载r0,该值不适合arm指令。汇编程序使用该语法执行的操作是它尝试在该指令可以放置数据值的代码内找到死点,然后将该指令编码为来自pc相对地址的加载。例如,无条件分支是隐藏数据的好地方。有时您必须使用像.pool这样的指令来鼓励或提醒汇编程序保留这些数据的好地方。 r0不是程序计数器r15,你可以使用r15将它连接到上面的分支讨论。

看看我为这个项目创建的汇编程序http://github.com/dwelch67/lsasim,一个固定长度的指令集,但我强迫用户分配单词并从中加载,我不允许arm汇编程序倾向于使用的快捷方式允许。

我希望这有助于解释事情。最重要的是,您无法在一次线性传递数据中解析标签,您必须返回并将点连接到前向引用的标签。而且我认为你必须做很多传递来解决所有的长/短编码(除非指令集/语法强制用户明确指定绝对vs相对分支,有些做rjmp vs jmp或rjmp vs ljmp,rcall vs电话等)。在"文件"上传一次当然,不是问题。如果你允许包含类型指令,一些工具会创建一个临时文件,它在创建一个没有包含的单个文件时提取所有包含,然后该工具对此进行一次传递(这是gcc管理包含的方式,例如,有时保存中间文件并查看生成的文件)(如果报告带有警告/错误的行号,则必须管理临时文件行与原始文件名和行。)。

答案 1 :(得分:2)

一个好的开始是David Solomon的书,Assemblers and Loaders。这是一本较旧的书,但信息仍然相关。

您可以下载PDF of the book