Assembly 使用寄存器vs值调用JMP的不同行为

Assembly 使用寄存器vs值调用JMP的不同行为,assembly,x86,gnu-assembler,intel-syntax,Assembly,X86,Gnu Assembler,Intel Syntax,我正在尝试执行到地址0x7C00的绝对跳转,这是操作系统中过程的一部分。我在GAS中使用intel语法,在QEMU中使用测试。我尝试了两种方法: jmp 0x00007c00 及 第二种方法似乎按照我的预期工作并跳转到0x7C00,但第一种方法导致QEMU崩溃,说明它“试图在0x40007c00的RAM或ROM之外执行代码”。有人知道为什么它跳转到另一个地址,而上面的字节被设置为0x4000吗 编辑: 分解时,我分别收到以下信息: 3c: e9 fc 7b 00 00

我正在尝试执行到地址0x7C00的绝对跳转,这是操作系统中过程的一部分。我在GAS中使用intel语法,在QEMU中使用测试。我尝试了两种方法:

jmp 0x00007c00

第二种方法似乎按照我的预期工作并跳转到0x7C00,但第一种方法导致QEMU崩溃,说明它“试图在0x40007c00的RAM或ROM之外执行代码”。有人知道为什么它跳转到另一个地址,而上面的字节被设置为0x4000吗

编辑:

分解时,我分别收到以下信息:

  3c:   e9 fc 7b 00 00          jmp    7c3d <int32_end+0x7ad4>

因此,它们的编译方式不同,尽管我仍然有点困惑第二个版本到底在做什么,这看起来像是跳转到0x7c3d。答案是评论中提到的一系列见解:

首先是分解代码,以查看jmp已组装成一个接近
JMPRel32
。事实证明,所有x86直接近跳都是相对的。显示此jmp正在使用的E9操作码的编码。要对右rel32偏移量进行编码以达到给定的绝对目标地址,汇编器+链接器需要知道跳转指令将从哪个地址运行

源代码中的
jmp 0x00007c00
为它提供了
0x00007c00
的绝对跳转目标,但汇编程序将通过相对跳转到达它。它与
jmp.+0x7c00
或直接指定rel32位移不同。如果指令本身在一个文件中写入两次,并将其汇编+链接到一个ELF可执行文件中(例如,
gcc-static-nostdlib foo.s&&objdump-drwC-Mintel a.out
),则可以很容易看出这一点。这里,两条jmp指令具有不同的编码(不同的rel32)和相同的绝对目标。此外,当观察最终elf时,您可以看到汇编程序到达
0x7C00
,并有一个相对的跳跃(由于代码地址从
0xC0100000
开始,因此为
0x3ff06723

我遇到的一个问题是,当我的代码应该从
0xc010000
开始时,地址和跳转看起来太小了。我没有意识到.o文件中的地址是相对于文件开头的,因此指令位于
0x3c
,这是它在文件中的偏移量。如果我分解链接后生成的最终elf文件,则所有地址都添加了
0xC0100000

另外值得注意的是,为了方便起见,反汇编程序正在根据该指令末尾显示的地址计算绝对地址
7c3d
。实际相对位移为小端值
fc 7b 00=0x00007bfc
。由于我正在分解一个.o文件,链接器还没有填充真正的位移。这可以通过使用
objdump-drwC-Mintel来避免。


为了使执行跳转的代码独立于位置,最好的方法是坚持第二种方法中使用的
mov immediate
+
jmp eax

答案是评论中提到的一系列见解:

首先是分解代码,以查看jmp已组装成一个接近
JMPRel32
。事实证明,所有x86直接近跳都是相对的。显示此jmp正在使用的E9操作码的编码。要对右rel32偏移量进行编码以达到给定的绝对目标地址,汇编器+链接器需要知道跳转指令将从哪个地址运行

源代码中的
jmp 0x00007c00
为它提供了
0x00007c00
的绝对跳转目标,但汇编程序将通过相对跳转到达它。它与
jmp.+0x7c00
或直接指定rel32位移不同。如果指令本身在一个文件中写入两次,并将其汇编+链接到一个ELF可执行文件中(例如,
gcc-static-nostdlib foo.s&&objdump-drwC-Mintel a.out
),则可以很容易看出这一点。这里,两条jmp指令具有不同的编码(不同的rel32)和相同的绝对目标。此外,当观察最终elf时,您可以看到汇编程序到达
0x7C00
,并有一个相对的跳跃(由于代码地址从
0xC0100000
开始,因此为
0x3ff06723

我遇到的一个问题是,当我的代码应该从
0xc010000
开始时,地址和跳转看起来太小了。我没有意识到.o文件中的地址是相对于文件开头的,因此指令位于
0x3c
,这是它在文件中的偏移量。如果我分解链接后生成的最终elf文件,则所有地址都添加了
0xC0100000

另外值得注意的是,为了方便起见,反汇编程序正在根据该指令末尾显示的地址计算绝对地址
7c3d
。实际相对位移为小端值
fc 7b 00=0x00007bfc
。由于我正在分解一个.o文件,链接器还没有填充真正的位移。这可以通过使用
objdump-drwC-Mintel来避免。


为了使执行跳转的代码与位置无关,最好的方法是坚持第二种方法中使用的
mov immediate
+
jmp eax

好的,这毕竟是合理的。但是,所有x86直接近跳都是相对的。显示您的
jmp
正在使用的E9操作码的编码。要对右
rel32
偏移量进行编码以达到给定的绝对目标地址,汇编程序+链接器需要知道跳转指令将从哪个地址运行。如果您希望执行跳转的代码与位置无关,最好的方法是mov immediate+
jmp eax
@23scurtu:不要忘记,不能保证BIOS存在(也不能保证固件不是UEFI或其他东西);一
  3c:   e9 fc 7b 00 00          jmp    7c3d <int32_end+0x7ad4>
  3c:   b8 00 7c 00 00          mov    $0x7c00,%eax
  41:   ff e0                   jmp    *%eax