涉及跳转时,代码行在汇编代码中的相互关系如何?

时间:2018-10-20 20:09:57

标签: assembly x86 machine-code

好的,所以我了解mov的含义,了解寄存器的内容,了解操作命令。我什至知道最左边的十六进制是指令的编号。例如,在第7行,十六进制7f是指令jg。精细。

我不明白的是这些事实究竟是如何相加的,令人难以置信的令人沮丧。

到目前为止我所知道的:

例如,第1行的0d是否加到804839c行?不,它跳到第17行,因为0d是第1行之后的指令。如果将地址804839e加0d,则会得到80483a7。好。

这是否意味着下一行的所有指令都相对于第二个2位十六进制?

这是否意味着当前行的指令是最左边的十六进制?

我只需要多一点指导,我已经很明白了,我几乎可以品尝到它了。

1 804839c: 7e 0d      jle   80483ab <silly+0x17>
2 804839e: 89 d0      mov   %edx,%eax
3 80483a0: d1 f8      sar   %eax
4 80483a2: 29 c2      sub   %eax,%edx
5 80483a4: 8d 14 52   lea   (%edx,%edx,2),%edx
6 80483a7: 85 d2      test  %edx,%edx
7 80483a9: 7f f3      jg    804839e <silly+0xa>
8 80483ab: 89 d0      mov   %edx,%eax 

2 个答案:

答案 0 :(得分:1)

在跳转指令(1)中使用的相对偏移量可以最好地理解如下:偏移量只是要添加的东西(它是一个带符号的值,因此您可以向前跳转 new 程序计数器。

但是这里要记住的重要一点是,程序计数器(向其添加偏移量)是指令 在跳转之后的位置。我总是以为CPU已经将程序计数器提前到下一个位置来记住这一点,以期获得下一条指令(2)

那很重要。根据您的示例代码(不相关的内容已删除):

1   804839c: 7e 0d      jle   80483ab <silly+0x17>
2   804839e: 89 d0      mov   %edx, %eax
3-7                     blah  blah, blah
8   80483ab: 89 d0      mov   %edx, %eax 

将偏移量0d添加到第二行804839e的位置,以获得第八行80483ab的跳转目标。


(1)并非 all 跳转指令都是相对的。只是您为问题选择了一个简短的形式,即操作码7e。您还可以选择近似形式的0f 8e。我认为不存在条件跳转的形式繁多的变体,您可以通过反转比较的方式来模拟它们,例如:

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

(2)因为在我开始为CPU切割原始代码的那一天就是这样做的。对于今天的流水线,投机执行等等,我不确定。

答案 1 :(得分:1)

如果您对操作码感到困惑,则距离理解它还有很长的路要走。您需要从说明集中的文档开始。对于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>

无需查看文档,非常清楚0x7E是操作码,而后面的字节是pc相对偏移量。前几项的0xFE表示它是一个有符号的偏移量,相对于指令后的字节。其余实验证实了这一点。

不是意味着您应该假设所有跳转/分支指令均以这种方式针对该指令集工作,您可以使用已知可产生工作代码的工具进行类似的实验。

这是一个缺少处理器文档的领域,通常需要1)如果可以的话,与芯片工程师交谈2)查看芯片设计(源代码)3)文档4)使用现有工具进行实验5)实验与硬件

大多数人没有访问1和2的权限。如果您实际上拥有这些处理器之一,则通常有3和4可用,通常要达到5则有3个处理器,并且您可能有4个访问权限,但有时却没有。但是同样,文档经常使相对地址未知,通常是指令后的字节,但是就像在ARM中一样,它是指令地址的固定偏移量,即特定管道的错觉。

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

804839c是jle指令yes的地址。 80483ab是满足条件时将跳转到的地址。 ab-9c = 0xf = 0xD +2。2是指令的大小,0xD是指令中的偏移量/立即数。

我会假定这种形式的其他条件分支(请注意,代码后面的jg)是操作码字节和带符号的偏移量字节。但是,在制作自己的汇编器,反汇编器或模拟器之前,应始终进行检查。从文档开始,然后使用您可以找到的适用于该平台的任何工具进行确认。