assembly - 跳出范围解决方案以及不同的指令如何影响范围

标签 assembly x86-16

我一直在为错误“jmp out of range”而苦苦挣扎,很多时候我需要从我的代码的不同部分运行一个子程序,就像我在 C++ 中运行一个函数一样。

我发现我的代码的两端都需要跳到同一个地方,而两者都无法到达那里。

解决这个问题的方法是什么?

我也注意到
PRINT 'something'
似乎比使用占用更多的“空间”:

CALL PTHIS
DB 13, 10, 'something', 0

(如果我在两次跳跃之间放一个 PRINT,我就会跳出范围,但如果我用 PTHIS 替换它,就没有问题)

为什么是这样?

最佳答案

16 位汇编器中条件跳转指令的问题在于它们的偏移量被限制为 +127 或 -128 字节。

386推出jcc rel16在 16 位模式下可用的编码,但仅适用于 386 及更高版本。不同的汇编器有不同的选项来启用 16 位代码中的 386 条指令

有些还可以选择自动执行以下描述的操作:条件 jcc rel8jmp rel16 .例如,TASM has /jJUMPS .

假设你有这个:

    cmp al, '1'
    jnz ItsNot1
    ; lots of code here
ItsNot1:

如果跳出范围错误,您可以像这样重新编码:
    cmp al, '1'
    jz Its1
    jmp ItsNot1
Its1:
    ; lots of code here
ItsNot1:

我所做的只是改变比较的意义,并绕过将您带到备用代码路径的无条件跳转。

如果你有很多条件跳转,有时会很烦人。您将重新编码其中一个,它会触发另一个。然后您重构代码并发现其中一些损坏的条件可以消失。通常我不担心它,除非我非常关心代码大小。

一些汇编程序有一个开关,可以为您自动调整跳转大小,以便您始终可以对条件跳转进行编码,并且它们会自动执行跳转条件跳转技巧。

最有可能的区别
PRINT 'something'


call PTHIS
db 13, 10, 'something'

第一个是一个宏,它扩展为用于打印某些内容的完整代码,以及您要打印的字符串。第二个是简单的call指令(3 个字节),加上字符串。或者,用 C++ 术语来说,PRINT宏就像一个内联函数,而 call PTHIS是一个普通的(非内联的)函数调用。

关于assembly - 跳出范围解决方案以及不同的指令如何影响范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17307834/

相关文章:

c++ - 如何在内联 ASM 中调用此函数? (MSVC++)

assembly - 如何在某处计算正弦值,然后移至汇编中的 XMM0 中?

c - 在 C 中使用内联汇编的错误

assembly - 汇编程序编译错误

assembly - 这个汇编代码中这一步需要什么 - x86

assembly - 无需操作系统即可打印字符串

c - 为什么键盘中断在 QEMU 中起作用,但在真实硬件上不起作用?

assembly - 无法在程序集中输出空格

windows - 是否有任何 FAT FS 驱动程序希望引导扇区的字节 508 和 509 为零?