assembly 当涉及跳转时,汇编代码中的代码行是如何相互关联的?

ugmeyewa  于 2023-08-06  发布在  其他
关注(0)|答案(2)|浏览(106)

好的,我明白mov的意思,我明白寄存器是什么,我明白操作命令是什么。我甚至知道最左边的十六进制是指令的编号。例如,在第7行,十六进制7f是指令jg。很好。
我不明白的是这些事实是如何加起来的,这令人难以置信的令人沮丧。

目前所知:

例如,在第1行,0d是否会添加到第804839c行?不,它跳到第17行,因为0d是第1行之后的指令。如果在地址804839e上加上0d,则得到80483a7。很好。
这是否意味着下一行的所有指令都是相对于第二个2位十六进制的?
这是否意味着最左边的十六进制是当前行的指令?
我只需要多一点方向,我是如此接近弄清楚这一点,我几乎可以品尝它。

lpwwtiir

lpwwtiir1#

在跳转指令(1)中使用的相对偏移可以被最好地理解如下:偏移量只是简单的添加(它是一个有符号的值,所以你可以向前 * 或向后 * 跳转,在有限的范围内)到程序计数器,以获得 * 新的 * 程序计数器。
但这里要记住的重要一点是,程序计数器(您添加偏移量的对象)是跳转后指令的位置。我总是记得这一点,因为我认为CPU已经将程序计数器推进到下一个位置,以预期得到下一条指令(2)。
这很重要根据你的示例代码(删除不相关的东西):
偏移量0d被添加到第二行的位置804839e,以获得第八行的跳转目标80483ab
(1)并不是所有的跳转指令都是相对的。只是你为你的问题选择了一个简短的形式,操作码7e。您也可以选择近似形式0f 8e。我不认为条件跳转的远形式变体存在,而是通过反转比较的意义来模拟这些变体,例如:

jle  farPoint    -->          jg   noJump
blah blah, blah               jmp  farPoint
                      noJump: blah blah, blah

字符串
(2)因为在我开始为CPU切割原始代码的时候,就是这样做的。有了今天的流水线、推测性执行等等,我就不那么确定了。

ia2d9nvy

ia2d9nvy2#

如果你对操作码感到困惑,你离理解这一点还有很长的路要走。您需要从指令集的文档开始。对于x86,这是足够的;这不是很好的文档,但操作码仍然很清楚。有了这样的指令集,就不难找到一个带有操作码图表的网页,然后点击它来找到指令定义的其余部分。
相对地址通常基于指令后的字节。如果你在一个全新的处理器团队工作,那么你只需要去一个芯片人员的立方体并询问(因为它还没有很好的文档记录),但由于这是一个旧的设计,有一些工具可以简单地给予你答案,而不需要问其他人。
试试这个:

a0: jle a0
a1: jle a1
a2: jle a2
a3: jle a3
a4: jle a4

b0: jle b1
b1: jle b2
b2: jle b3
b3: jle b4
b4: jle b5
b5: nop

c0: jle c0
c1: jle c0
c2: jle c0
c3: jle c0
c4: jle c0

d0: jle d4
d1: jle d4
d2: jle d4
d3: jle d4
d4: jle d4

字符串
组装和拆卸:

0000000000000000 <a0>:
   0:   7e fe                   jle    0 <a0>
0000000000000002 <a1>:
   2:   7e fe                   jle    2 <a1>
0000000000000004 <a2>:
   4:   7e fe                   jle    4 <a2>
0000000000000006 <a3>:
   6:   7e fe                   jle    6 <a3>
0000000000000008 <a4>:
   8:   7e fe                   jle    8 <a4>
000000000000000a <b0>:
   a:   7e 00                   jle    c <b1>
000000000000000c <b1>:
   c:   7e 00                   jle    e <b2>
000000000000000e <b2>:
   e:   7e 00                   jle    10 <b3>
0000000000000010 <b3>:
  10:   7e 00                   jle    12 <b4>
0000000000000012 <b4>:
  12:   7e 00                   jle    14 <b5>
0000000000000014 <b5>:
  14:   90                      nop
0000000000000015 <c0>:
  15:   7e fe                   jle    15 <c0>
0000000000000017 <c1>:
  17:   7e fc                   jle    15 <c0>
0000000000000019 <c2>:
  19:   7e fa                   jle    15 <c0>
000000000000001b <c3>:
  1b:   7e f8                   jle    15 <c0>
000000000000001d <c4>:
  1d:   7e f6                   jle    15 <c0>
000000000000001f <d0>:
  1f:   7e 06                   jle    27 <d4>
0000000000000021 <d1>:
  21:   7e 04                   jle    27 <d4>
0000000000000023 <d2>:
  23:   7e 02                   jle    27 <d4>
0000000000000025 <d3>:
  25:   7e 00                   jle    27 <d4>
0000000000000027 <d4>:
  27:   7e fe                   jle    27 <d4>


不用看文档,0x 7 E是一个操作码,后面的字节是pc的相对偏移量。第一项上的0xFE意味着它是有符号偏移量,并且相对于指令之后的字节。剩下的实验证实了这一点。
这并不意味着你应该假设所有的跳转/分支指令都是这样工作的,你可以用已知的能产生工作代码的工具做类似的实验。
这是一个缺乏处理器文档的领域,您通常需要1)与芯片工程师交谈(如果可以的话)2)查看芯片设计(源代码)3)文档4)使用现有工具进行实验5)使用硬件进行实验
大多数人都无法获得1和2。通常3和4是可用的,如果你实际上有一个这些处理器,通常要达到5,你有3,你可能有访问4,但有时没有。但是,文档中经常会留下未知的相对地址,通常是指令后面的字节,但与ARM一样,它是指令地址的固定偏移量,这是特定流水线的错觉。

804839c: 7e 0d      jle   80483ab <silly+0x17>


804839 c是jle指令yes的地址。80483 ab是在满足条件时将分支到的地址。ab-9c = 0xf = 0xD + 2。2是指令的大小,0xD是指令中的偏移量/立即数。
我假设这种形式的其他条件分支(注意代码后面的jg)是一个操作码字节和一个带符号的偏移字节。但是在制作自己的汇编器、反汇编器或模拟器之前,你应该经常检查一下。从文档开始,并使用您可以找到的任何已知适用于该平台的工具进行确认。

相关问题